4 spaces files harmonisation #184

This commit is contained in:
J-Jamet
2019-07-04 14:34:06 +02:00
parent 93222990b5
commit e4b550afc1
58 changed files with 3394 additions and 3392 deletions

View File

@@ -1,22 +1,22 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.tests;
import android.test.AndroidTestCase;
@@ -24,19 +24,21 @@ import android.test.AndroidTestCase;
import com.kunzisoft.keepass.tests.database.TestData;
public class AccentTest extends AndroidTestCase {
private static final String KEYFILE = "";
private static final String PASSWORD = "é";
private static final String ASSET = "accent.kdb";
private static final String FILENAME = "/sdcard/accent.kdb";
public void testOpen() {
try {
TestData.GetDb(getContext(), ASSET, PASSWORD, KEYFILE, FILENAME);
} catch (Exception e) {
assertTrue("Failed to open database", false);
}
}
private static final String KEYFILE = "";
private static final String PASSWORD = "é";
private static final String ASSET = "accent.kdb";
private static final String FILENAME = "/sdcard/accent.kdb";
public void testOpen() {
/*
try {
TestData.GetDb(getContext(), ASSET, PASSWORD, KEYFILE, FILENAME);
} catch (Exception e) {
assertTrue("Failed to open database", false);
}
*/
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -26,10 +26,10 @@ import android.test.suitebuilder.TestSuiteBuilder;
public class OutputTests extends TestSuite {
public static Test suite() {
public static Test suite() {
return new TestSuiteBuilder(AllTests.class)
.includePackages("com.kunzisoft.keepass.tests.output")
.build();
}
return new TestSuiteBuilder(AllTests.class)
.includePackages("com.kunzisoft.keepass.tests.output")
.build();
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -24,15 +24,15 @@ import junit.framework.TestCase;
import com.kunzisoft.keepass.database.element.PwDate;
public class PwDateTest extends TestCase {
public void testDate() {
PwDate jDate = new PwDate(System.currentTimeMillis());
PwDate intermediate = new PwDate(jDate);
PwDate cDate = new PwDate(intermediate.getCDate(), 0);
assertTrue("jDate and intermediate not equal", jDate.equals(intermediate));
assertTrue("jDate and cDate not equal", cDate.equals(jDate));
}
public void testDate() {
PwDate jDate = new PwDate(System.currentTimeMillis());
PwDate intermediate = new PwDate(jDate);
PwDate cDate = new PwDate(intermediate.getCDate(), 0);
assertTrue("jDate and intermediate not equal", jDate.equals(intermediate));
assertTrue("jDate and cDate not equal", cDate.equals(jDate));
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -31,33 +31,33 @@ import com.kunzisoft.keepass.database.element.PwEntryV3;
import com.kunzisoft.keepass.tests.database.TestData;
public class PwEntryTestV3 extends AndroidTestCase {
PwEntryV3 mPE;
@Override
protected void setUp() throws Exception {
super.setUp();
// mPE = (PwEntryV3) TestData.GetTest1(getContext()).getEntryAt(0);
}
public void testName() {
assertTrue("Name was " + mPE.getTitle(), mPE.getTitle().equals("Amazon"));
}
public void testPassword() throws UnsupportedEncodingException {
String sPass = "12345";
byte[] password = sPass.getBytes("UTF-8");
assertArrayEquals(password, mPE.getPasswordBytes());
}
public void testCreation() {
Calendar cal = Calendar.getInstance();
cal.setTime(mPE.getCreationTime().getDate());
assertEquals("Incorrect year.", cal.get(Calendar.YEAR), 2009);
assertEquals("Incorrect month.", cal.get(Calendar.MONTH), 3);
assertEquals("Incorrect day.", cal.get(Calendar.DAY_OF_MONTH), 23);
}
PwEntryV3 mPE;
@Override
protected void setUp() throws Exception {
super.setUp();
// mPE = (PwEntryV3) TestData.GetTest1(getContext()).getEntryAt(0);
}
public void testName() {
assertTrue("Name was " + mPE.getTitle(), mPE.getTitle().equals("Amazon"));
}
public void testPassword() throws UnsupportedEncodingException {
String sPass = "12345";
byte[] password = sPass.getBytes("UTF-8");
assertArrayEquals(password, mPE.getPasswordBytes());
}
public void testCreation() {
Calendar cal = Calendar.getInstance();
cal.setTime(mPE.getCreationTime().getDate());
assertEquals("Incorrect year.", cal.get(Calendar.YEAR), 2009);
assertEquals("Incorrect month.", cal.get(Calendar.MONTH), 3);
assertEquals("Incorrect day.", cal.get(Calendar.DAY_OF_MONTH), 23);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.tests;
import junit.framework.TestCase;
public class PwEntryTestV4 extends TestCase {
public void testAssign() {
public void testAssign() {
/*
TODO Test
PwEntryV4 entry = new PwEntryV4();
@@ -53,7 +53,7 @@ public class PwEntryTestV4 extends TestCase {
/* This test is not so useful now that I am not implementing value equality for Entries
assertTrue("Entries do not match.", entry.equals(target));
*/
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -27,18 +27,18 @@ import com.kunzisoft.keepass.tests.database.TestData;
public class PwGroupTest extends AndroidTestCase {
PwGroupV3 mPG;
@Override
protected void setUp() throws Exception {
super.setUp();
//mPG = (PwGroupV3) TestData.GetTest1(getContext()).getGroups().get(0);
}
public void testGroupName() {
//assertTrue("Name was " + mPG.getTitle(), mPG.getTitle().equals("Internet"));
}
PwGroupV3 mPG;
@Override
protected void setUp() throws Exception {
super.setUp();
//mPG = (PwGroupV3) TestData.GetTest1(getContext()).getGroups().get(0);
}
public void testGroupName() {
//assertTrue("Name was " + mPG.getTitle(), mPG.getTitle().equals("Internet"));
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -33,29 +33,29 @@ import com.kunzisoft.keepass.utils.EmptyUtils;
import com.kunzisoft.keepass.utils.UriUtil;
public class TestUtil {
private static final File sdcard = Environment.getExternalStorageDirectory();
private static final File sdcard = Environment.getExternalStorageDirectory();
public static void extractKey(Context ctx, String asset, String target) throws Exception {
InputStream key = ctx.getAssets().open(asset, AssetManager.ACCESS_STREAMING);
FileOutputStream keyFile = new FileOutputStream(target);
while (true) {
byte[] buf = new byte[1024];
int read = key.read(buf);
if ( read == -1 ) {
break;
} else {
keyFile.write(buf, 0, read);
}
}
keyFile.close();
public static void extractKey(Context ctx, String asset, String target) throws Exception {
}
InputStream key = ctx.getAssets().open(asset, AssetManager.ACCESS_STREAMING);
public static String getSdPath(String filename) {
File file = new File(sdcard, filename);
return file.getAbsolutePath();
}
FileOutputStream keyFile = new FileOutputStream(target);
while (true) {
byte[] buf = new byte[1024];
int read = key.read(buf);
if ( read == -1 ) {
break;
} else {
keyFile.write(buf, 0, read);
}
}
keyFile.close();
}
public static String getSdPath(String filename) {
File file = new File(sdcard, filename);
return file.getAbsolutePath();
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -35,177 +35,177 @@ import com.kunzisoft.keepass.utils.Types;
public class TypesTest extends TestCase {
public void testReadWriteLongZero() {
testReadWriteLong((byte) 0);
}
public void testReadWriteLongMax() {
testReadWriteLong(Byte.MAX_VALUE);
}
public void testReadWriteLongMin() {
testReadWriteLong(Byte.MIN_VALUE);
}
public void testReadWriteLongRnd() {
Random rnd = new Random();
byte[] buf = new byte[1];
rnd.nextBytes(buf);
testReadWriteLong(buf[0]);
}
private void testReadWriteLong(byte value) {
byte[] orig = new byte[8];
byte[] dest = new byte[8];
setArray(orig, value, 0, 8);
long one = LEDataInputStream.readLong(orig, 0);
LEDataOutputStream.writeLong(one, dest, 0);
assertArrayEquals(orig, dest);
public void testReadWriteLongZero() {
testReadWriteLong((byte) 0);
}
}
public void testReadWriteIntZero() {
testReadWriteInt((byte) 0);
}
public void testReadWriteIntMin() {
testReadWriteInt(Byte.MIN_VALUE);
}
public void testReadWriteIntMax() {
testReadWriteInt(Byte.MAX_VALUE);
}
private void testReadWriteInt(byte value) {
byte[] orig = new byte[4];
byte[] dest = new byte[4];
for (int i = 0; i < 4; i++ ) {
orig[i] = 0;
}
setArray(orig, value, 0, 4);
int one = LEDataInputStream.readInt(orig, 0);
LEDataOutputStream.writeInt(one, dest, 0);
public void testReadWriteLongMax() {
testReadWriteLong(Byte.MAX_VALUE);
}
assertArrayEquals(orig, dest);
}
private void setArray(byte[] buf, byte value, int offset, int size) {
for (int i = offset; i < offset + size; i++) {
buf[i] = value;
}
}
public void testReadWriteShortOne() {
byte[] orig = new byte[2];
byte[] dest = new byte[2];
orig[0] = 0;
orig[1] = 1;
int one = LEDataInputStream.readUShort(orig, 0);
dest = LEDataOutputStream.writeUShortBuf(one);
assertArrayEquals(orig, dest);
}
public void testReadWriteShortMin() {
testReadWriteShort(Byte.MIN_VALUE);
}
public void testReadWriteShortMax() {
testReadWriteShort(Byte.MAX_VALUE);
}
private void testReadWriteShort(byte value) {
byte[] orig = new byte[2];
byte[] dest = new byte[2];
setArray(orig, value, 0, 2);
int one = LEDataInputStream.readUShort(orig, 0);
LEDataOutputStream.writeUShort(one, dest, 0);
assertArrayEquals(orig, dest);
public void testReadWriteLongMin() {
testReadWriteLong(Byte.MIN_VALUE);
}
}
public void testReadWriteLongRnd() {
Random rnd = new Random();
byte[] buf = new byte[1];
rnd.nextBytes(buf);
public void testReadWriteByteZero() {
testReadWriteByte((byte) 0);
}
public void testReadWriteByteMin() {
testReadWriteByte(Byte.MIN_VALUE);
}
public void testReadWriteByteMax() {
testReadWriteShort(Byte.MAX_VALUE);
}
private void testReadWriteByte(byte value) {
byte[] orig = new byte[1];
byte[] dest = new byte[1];
setArray(orig, value, 0, 1);
int one = Types.readUByte(orig, 0);
Types.writeUByte(one, dest, 0);
assertArrayEquals(orig, dest);
}
public void testDate() {
Calendar cal = Calendar.getInstance();
Calendar expected = Calendar.getInstance();
expected.set(2008, 1, 2, 3, 4, 5);
byte[] buf = PwDate.writeTime(expected.getTime(), cal);
Calendar actual = Calendar.getInstance();
actual.setTime(PwDate.readTime(buf, 0, cal));
assertEquals("Year mismatch: ", 2008, actual.get(Calendar.YEAR));
assertEquals("Month mismatch: ", 1, actual.get(Calendar.MONTH));
assertEquals("Day mismatch: ", 1, actual.get(Calendar.DAY_OF_MONTH));
assertEquals("Hour mismatch: ", 3, actual.get(Calendar.HOUR_OF_DAY));
assertEquals("Minute mismatch: ", 4, actual.get(Calendar.MINUTE));
assertEquals("Second mismatch: ", 5, actual.get(Calendar.SECOND));
}
public void testUUID() {
Random rnd = new Random();
byte[] bUUID = new byte[16];
rnd.nextBytes(bUUID);
UUID uuid = Types.bytestoUUID(bUUID);
byte[] eUUID = Types.UUIDtoBytes(uuid);
assertArrayEquals("UUID match failed", bUUID, eUUID);
}
testReadWriteLong(buf[0]);
}
public void testULongMax() throws Exception {
byte[] ulongBytes = new byte[8];
for (int i = 0; i < ulongBytes.length; i++) {
ulongBytes[i] = -1;
}
private void testReadWriteLong(byte value) {
byte[] orig = new byte[8];
byte[] dest = new byte[8];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
LEDataOutputStream leos = new LEDataOutputStream(bos);
leos.writeLong(Types.ULONG_MAX_VALUE);
leos.close();
setArray(orig, value, 0, 8);
byte[] uLongMax = bos.toByteArray();
long one = LEDataInputStream.readLong(orig, 0);
LEDataOutputStream.writeLong(one, dest, 0);
assertArrayEquals(ulongBytes, uLongMax);
}
assertArrayEquals(orig, dest);
}
public void testReadWriteIntZero() {
testReadWriteInt((byte) 0);
}
public void testReadWriteIntMin() {
testReadWriteInt(Byte.MIN_VALUE);
}
public void testReadWriteIntMax() {
testReadWriteInt(Byte.MAX_VALUE);
}
private void testReadWriteInt(byte value) {
byte[] orig = new byte[4];
byte[] dest = new byte[4];
for (int i = 0; i < 4; i++ ) {
orig[i] = 0;
}
setArray(orig, value, 0, 4);
int one = LEDataInputStream.readInt(orig, 0);
LEDataOutputStream.writeInt(one, dest, 0);
assertArrayEquals(orig, dest);
}
private void setArray(byte[] buf, byte value, int offset, int size) {
for (int i = offset; i < offset + size; i++) {
buf[i] = value;
}
}
public void testReadWriteShortOne() {
byte[] orig = new byte[2];
byte[] dest = new byte[2];
orig[0] = 0;
orig[1] = 1;
int one = LEDataInputStream.readUShort(orig, 0);
dest = LEDataOutputStream.writeUShortBuf(one);
assertArrayEquals(orig, dest);
}
public void testReadWriteShortMin() {
testReadWriteShort(Byte.MIN_VALUE);
}
public void testReadWriteShortMax() {
testReadWriteShort(Byte.MAX_VALUE);
}
private void testReadWriteShort(byte value) {
byte[] orig = new byte[2];
byte[] dest = new byte[2];
setArray(orig, value, 0, 2);
int one = LEDataInputStream.readUShort(orig, 0);
LEDataOutputStream.writeUShort(one, dest, 0);
assertArrayEquals(orig, dest);
}
public void testReadWriteByteZero() {
testReadWriteByte((byte) 0);
}
public void testReadWriteByteMin() {
testReadWriteByte(Byte.MIN_VALUE);
}
public void testReadWriteByteMax() {
testReadWriteShort(Byte.MAX_VALUE);
}
private void testReadWriteByte(byte value) {
byte[] orig = new byte[1];
byte[] dest = new byte[1];
setArray(orig, value, 0, 1);
int one = Types.readUByte(orig, 0);
Types.writeUByte(one, dest, 0);
assertArrayEquals(orig, dest);
}
public void testDate() {
Calendar cal = Calendar.getInstance();
Calendar expected = Calendar.getInstance();
expected.set(2008, 1, 2, 3, 4, 5);
byte[] buf = PwDate.writeTime(expected.getTime(), cal);
Calendar actual = Calendar.getInstance();
actual.setTime(PwDate.readTime(buf, 0, cal));
assertEquals("Year mismatch: ", 2008, actual.get(Calendar.YEAR));
assertEquals("Month mismatch: ", 1, actual.get(Calendar.MONTH));
assertEquals("Day mismatch: ", 1, actual.get(Calendar.DAY_OF_MONTH));
assertEquals("Hour mismatch: ", 3, actual.get(Calendar.HOUR_OF_DAY));
assertEquals("Minute mismatch: ", 4, actual.get(Calendar.MINUTE));
assertEquals("Second mismatch: ", 5, actual.get(Calendar.SECOND));
}
public void testUUID() {
Random rnd = new Random();
byte[] bUUID = new byte[16];
rnd.nextBytes(bUUID);
UUID uuid = Types.bytestoUUID(bUUID);
byte[] eUUID = Types.UUIDtoBytes(uuid);
assertArrayEquals("UUID match failed", bUUID, eUUID);
}
public void testULongMax() throws Exception {
byte[] ulongBytes = new byte[8];
for (int i = 0; i < ulongBytes.length; i++) {
ulongBytes[i] = -1;
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
LEDataOutputStream leos = new LEDataOutputStream(bos);
leos.writeLong(Types.ULONG_MAX_VALUE);
leos.close();
byte[] uLongMax = bos.toByteArray();
assertArrayEquals(ulongBytes, uLongMax);
}
}

View File

@@ -1,22 +1,22 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.tests.crypto;
import com.kunzisoft.keepass.crypto.CipherFactory;
@@ -38,46 +38,46 @@ import javax.crypto.spec.SecretKeySpec;
import static org.junit.Assert.assertArrayEquals;
public class AESTest extends TestCase {
private Random mRand = new Random();
public void testEncrypt() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
// Test above below and at the blocksize
testFinal(15);
testFinal(16);
testFinal(17);
// Test random larger sizes
int size = mRand.nextInt(494) + 18;
testFinal(size);
}
private void testFinal(int dataSize) throws NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
// Generate some input
byte[] input = new byte[dataSize];
mRand.nextBytes(input);
// Generate key
byte[] keyArray = new byte[32];
mRand.nextBytes(keyArray);
SecretKeySpec key = new SecretKeySpec(keyArray, "AES");
// Generate IV
byte[] ivArray = new byte[16];
mRand.nextBytes(ivArray);
IvParameterSpec iv = new IvParameterSpec(ivArray);
Cipher android = CipherFactory.getInstance("AES/CBC/PKCS5Padding", true);
android.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] outAndroid = android.doFinal(input, 0, dataSize);
Cipher nat = CipherFactory.getInstance("AES/CBC/PKCS5Padding");
nat.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] outNative = nat.doFinal(input, 0, dataSize);
assertArrayEquals("Arrays differ on size: " + dataSize, outAndroid, outNative);
}
private Random mRand = new Random();
public void testEncrypt() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
// Test above below and at the blocksize
testFinal(15);
testFinal(16);
testFinal(17);
// Test random larger sizes
int size = mRand.nextInt(494) + 18;
testFinal(size);
}
private void testFinal(int dataSize) throws NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
// Generate some input
byte[] input = new byte[dataSize];
mRand.nextBytes(input);
// Generate key
byte[] keyArray = new byte[32];
mRand.nextBytes(keyArray);
SecretKeySpec key = new SecretKeySpec(keyArray, "AES");
// Generate IV
byte[] ivArray = new byte[16];
mRand.nextBytes(ivArray);
IvParameterSpec iv = new IvParameterSpec(ivArray);
Cipher android = CipherFactory.getInstance("AES/CBC/PKCS5Padding", true);
android.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] outAndroid = android.doFinal(input, 0, dataSize);
Cipher nat = CipherFactory.getInstance("AES/CBC/PKCS5Padding");
nat.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] outNative = nat.doFinal(input, 0, dataSize);
assertArrayEquals("Arrays differ on size: " + dataSize, outAndroid, outNative);
}
}

View File

@@ -1,22 +1,22 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.tests.crypto;
import static org.junit.Assert.assertArrayEquals;
@@ -44,57 +44,57 @@ import com.kunzisoft.keepass.stream.BetterCipherInputStream;
import com.kunzisoft.keepass.stream.LEDataInputStream;
public class CipherTest extends TestCase {
private Random rand = new Random();
public void testCipherFactory() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] key = new byte[32];
byte[] iv = new byte[16];
byte[] plaintext = new byte[1024];
rand.nextBytes(key);
rand.nextBytes(iv);
rand.nextBytes(plaintext);
CipherEngine aes = CipherFactory.getInstance(AesEngine.CIPHER_UUID);
Cipher encrypt = aes.getCipher(Cipher.ENCRYPT_MODE, key, iv);
Cipher decrypt = aes.getCipher(Cipher.DECRYPT_MODE, key, iv);
private Random rand = new Random();
byte[] secrettext = encrypt.doFinal(plaintext);
byte[] decrypttext = decrypt.doFinal(secrettext);
assertArrayEquals("Encryption and decryption failed", plaintext, decrypttext);
}
public void testCipherFactory() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] key = new byte[32];
byte[] iv = new byte[16];
public void testCipherStreams() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException {
final int MESSAGE_LENGTH = 1024;
byte[] key = new byte[32];
byte[] iv = new byte[16];
byte[] plaintext = new byte[MESSAGE_LENGTH];
rand.nextBytes(key);
rand.nextBytes(iv);
rand.nextBytes(plaintext);
byte[] plaintext = new byte[1024];
CipherEngine aes = CipherFactory.getInstance(AesEngine.CIPHER_UUID);
Cipher encrypt = aes.getCipher(Cipher.ENCRYPT_MODE, key, iv);
Cipher decrypt = aes.getCipher(Cipher.DECRYPT_MODE, key, iv);
rand.nextBytes(key);
rand.nextBytes(iv);
rand.nextBytes(plaintext);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(bos, encrypt);
cos.write(plaintext);
cos.close();
byte[] secrettext = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(secrettext);
BetterCipherInputStream cis = new BetterCipherInputStream(bis, decrypt);
LEDataInputStream lis = new LEDataInputStream(cis);
byte[] decrypttext = lis.readBytes(MESSAGE_LENGTH);
assertArrayEquals("Encryption and decryption failed", plaintext, decrypttext);
}
CipherEngine aes = CipherFactory.getInstance(AesEngine.CIPHER_UUID);
Cipher encrypt = aes.getCipher(Cipher.ENCRYPT_MODE, key, iv);
Cipher decrypt = aes.getCipher(Cipher.DECRYPT_MODE, key, iv);
byte[] secrettext = encrypt.doFinal(plaintext);
byte[] decrypttext = decrypt.doFinal(secrettext);
assertArrayEquals("Encryption and decryption failed", plaintext, decrypttext);
}
public void testCipherStreams() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException {
final int MESSAGE_LENGTH = 1024;
byte[] key = new byte[32];
byte[] iv = new byte[16];
byte[] plaintext = new byte[MESSAGE_LENGTH];
rand.nextBytes(key);
rand.nextBytes(iv);
rand.nextBytes(plaintext);
CipherEngine aes = CipherFactory.getInstance(AesEngine.CIPHER_UUID);
Cipher encrypt = aes.getCipher(Cipher.ENCRYPT_MODE, key, iv);
Cipher decrypt = aes.getCipher(Cipher.DECRYPT_MODE, key, iv);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(bos, encrypt);
cos.write(plaintext);
cos.close();
byte[] secrettext = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(secrettext);
BetterCipherInputStream cis = new BetterCipherInputStream(bis, decrypt);
LEDataInputStream lis = new LEDataInputStream(cis);
byte[] decrypttext = lis.readBytes(MESSAGE_LENGTH);
assertArrayEquals("Encryption and decryption failed", plaintext, decrypttext);
}
}

View File

@@ -1,22 +1,22 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.tests.crypto;
import static org.junit.Assert.assertArrayEquals;
@@ -30,37 +30,37 @@ import com.kunzisoft.keepass.crypto.finalkey.AndroidFinalKey;
import com.kunzisoft.keepass.crypto.finalkey.NativeFinalKey;
public class FinalKeyTest extends TestCase {
private Random mRand;
@Override
protected void setUp() throws Exception {
super.setUp();
mRand = new Random();
}
public void testNativeAndroid() throws IOException {
// Test both an old and an even number to test my flip variable
testNativeFinalKey(5);
testNativeFinalKey(6);
}
private void testNativeFinalKey(int rounds) throws IOException {
byte[] seed = new byte[32];
byte[] key = new byte[32];
byte[] nativeKey;
byte[] androidKey;
mRand.nextBytes(seed);
mRand.nextBytes(key);
AndroidFinalKey aKey = new AndroidFinalKey();
androidKey = aKey.transformMasterKey(seed, key, rounds);
NativeFinalKey nKey = new NativeFinalKey();
nativeKey = nKey.transformMasterKey(seed, key, rounds);
assertArrayEquals("Does not match", androidKey, nativeKey);
}
private Random mRand;
@Override
protected void setUp() throws Exception {
super.setUp();
mRand = new Random();
}
public void testNativeAndroid() throws IOException {
// Test both an old and an even number to test my flip variable
testNativeFinalKey(5);
testNativeFinalKey(6);
}
private void testNativeFinalKey(int rounds) throws IOException {
byte[] seed = new byte[32];
byte[] key = new byte[32];
byte[] nativeKey;
byte[] androidKey;
mRand.nextBytes(seed);
mRand.nextBytes(key);
AndroidFinalKey aKey = new AndroidFinalKey();
androidKey = aKey.transformMasterKey(seed, key, rounds);
NativeFinalKey nKey = new NativeFinalKey();
nativeKey = nKey.transformMasterKey(seed, key, rounds);
assertArrayEquals("Does not match", androidKey, nativeKey);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -26,15 +26,15 @@ import com.kunzisoft.keepass.database.element.PwDatabaseV3;
import com.kunzisoft.keepass.database.element.PwEntryV3;
public class DeleteEntry extends AndroidTestCase {
private static final String GROUP1_NAME = "Group1";
private static final String ENTRY1_NAME = "Test1";
private static final String ENTRY2_NAME = "Test2";
private static final String KEYFILE = "";
private static final String PASSWORD = "12345";
private static final String ASSET = "delete.kdb";
private static final String FILENAME = "/sdcard/delete.kdb";
public void testDelete() {
private static final String GROUP1_NAME = "Group1";
private static final String ENTRY1_NAME = "Test1";
private static final String ENTRY2_NAME = "Test2";
private static final String KEYFILE = "";
private static final String PASSWORD = "12345";
private static final String ASSET = "delete.kdb";
private static final String FILENAME = "/sdcard/delete.kdb";
public void testDelete() {
/*
Database db;
@@ -76,9 +76,9 @@ public class DeleteEntry extends AndroidTestCase {
assertNull("Group 1 was not removed.", group1);
*/
}
private PwEntryV3 getEntry(PwDatabaseV3 pm, String name) {
}
private PwEntryV3 getEntry(PwDatabaseV3 pm, String name) {
/*
TODO test
List<PwEntryV3> entries = pm.getEntries();
@@ -89,11 +89,11 @@ public class DeleteEntry extends AndroidTestCase {
}
}
*/
return null;
}
private GroupVersioned getGroup(PwDatabase pm, String name) {
return null;
}
private GroupVersioned getGroup(PwDatabase pm, String name) {
/*
List<GroupVersioned> groups = pm.getGroups();
for ( int i = 0; i < groups.size(); i++ ) {
@@ -103,9 +103,9 @@ public class DeleteEntry extends AndroidTestCase {
}
}
*/
return null;
}
return null;
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -26,7 +26,7 @@ import junit.framework.TestCase;
public class EntryV4 extends TestCase {
public void testBackup() {
public void testBackup() {
/*
PwDatabaseV4 db = new PwDatabaseV4();
@@ -51,6 +51,6 @@ public class EntryV4 extends TestCase {
assertEquals("Title2", backup.getTitle());
assertEquals("User2", backup.getUsername());
*/
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -22,8 +22,8 @@ package com.kunzisoft.keepass.tests.database;
import android.test.AndroidTestCase;
public class Kdb3 extends AndroidTestCase {
private void testKeyfile(String dbAsset, String keyAsset, String password) throws Exception {
private void testKeyfile(String dbAsset, String keyAsset, String password) throws Exception {
/*
Context ctx = getContext();
@@ -40,14 +40,14 @@ public class Kdb3 extends AndroidTestCase {
is.close();
*/
}
public void testXMLKeyFile() throws Exception {
testKeyfile("kdb_with_xml_keyfile.kdb", "keyfile.key", "12345");
}
public void testBinary64KeyFile() throws Exception {
testKeyfile("binary-key.kdb", "binary.key", "12345");
}
}
public void testXMLKeyFile() throws Exception {
testKeyfile("kdb_with_xml_keyfile.kdb", "keyfile.key", "12345");
}
public void testBinary64KeyFile() throws Exception {
testKeyfile("binary-key.kdb", "binary.key", "12345");
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.tests.database;
import android.test.AndroidTestCase;
public class Kdb3Twofish extends AndroidTestCase {
public void testReadTwofish() throws Exception {
public void testReadTwofish() throws Exception {
/*
Context ctx = getContext();
@@ -37,5 +37,5 @@ public class Kdb3Twofish extends AndroidTestCase {
is.close();
*/
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -26,11 +26,11 @@ import android.test.AndroidTestCase;
import java.io.InputStream;
public class Kdb4Header extends AndroidTestCase {
public void testReadHeader() throws Exception {
Context ctx = getContext();
AssetManager am = ctx.getAssets();
InputStream is = am.open("test.kdbx", AssetManager.ACCESS_STREAMING);
public void testReadHeader() throws Exception {
Context ctx = getContext();
AssetManager am = ctx.getAssets();
InputStream is = am.open("test.kdbx", AssetManager.ACCESS_STREAMING);
/*
TODO Test
@@ -45,5 +45,5 @@ public class Kdb4Header extends AndroidTestCase {
is.close();
*/
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -35,17 +35,17 @@ import java.util.UUID;
import biz.source_code.base64Coder.Base64Coder;
public class SprEngineTest extends AndroidTestCase {
private PwDatabaseV4 db;
private SprEngineV4 spr;
@Override
protected void setUp() throws Exception {
super.setUp();
Context ctx = getContext();
AssetManager am = ctx.getAssets();
InputStream is = am.open("test.kdbx", AssetManager.ACCESS_STREAMING);
private PwDatabaseV4 db;
private SprEngineV4 spr;
@Override
protected void setUp() throws Exception {
super.setUp();
Context ctx = getContext();
AssetManager am = ctx.getAssets();
InputStream is = am.open("test.kdbx", AssetManager.ACCESS_STREAMING);
/*
TODO Test
@@ -56,12 +56,12 @@ public class SprEngineTest extends AndroidTestCase {
spr = new SprEngineV4();
*/
}
private final String REF = "{REF:P@I:2B1D56590D961F48A8CE8C392CE6CD35}";
private final String ENCODE_UUID = "IN7RkON49Ui1UZ2ddqmLcw==";
private final String RESULT = "Password";
public void testRefReplace() {
}
private final String REF = "{REF:P@I:2B1D56590D961F48A8CE8C392CE6CD35}";
private final String ENCODE_UUID = "IN7RkON49Ui1UZ2ddqmLcw==";
private final String RESULT = "Password";
public void testRefReplace() {
/*
TODO TEST
UUID entryUUID = decodeUUID(ENCODE_UUID);
@@ -71,16 +71,16 @@ public class SprEngineTest extends AndroidTestCase {
assertEquals(RESULT, spr.compile(REF, entry, db));
*/
}
private UUID decodeUUID(String encoded) {
if (encoded == null || encoded.length() == 0 ) {
return PwDatabase.UUID_ZERO;
}
byte[] buf = Base64Coder.decode(encoded);
return Types.bytestoUUID(buf);
}
}
private UUID decodeUUID(String encoded) {
if (encoded == null || encoded.length() == 0 ) {
return PwDatabase.UUID_ZERO;
}
byte[] buf = Base64Coder.decode(encoded);
return Types.bytestoUUID(buf);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -22,11 +22,11 @@ package com.kunzisoft.keepass.tests.database;
import com.kunzisoft.keepass.database.element.Database;
public class TestData {
private static final String TEST1_KEYFILE = "";
private static final String TEST1_KDB = "test1.kdb";
private static final String TEST1_PASSWORD = "12345";
private static final String TEST1_KEYFILE = "";
private static final String TEST1_KDB = "test1.kdb";
private static final String TEST1_PASSWORD = "12345";
private static Database mDb1;
private static Database mDb1;
/*

View File

@@ -1,22 +1,22 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.tests.search;
@@ -28,43 +28,43 @@ import com.kunzisoft.keepass.database.element.Database;
import com.kunzisoft.keepass.database.element.GroupVersioned;
public class SearchTest extends AndroidTestCase {
private Database mDb;
@Override
protected void setUp() throws Exception {
super.setUp();
//mDb = TestData.GetDb1(getContext(), true);
}
public void testSearch() {
GroupVersioned results = mDb.search("Amazon");
//assertTrue("Search result not found.", results.numbersOfChildEntries() > 0);
}
public void testBackupIncluded() {
updateOmitSetting(false);
GroupVersioned results = mDb.search("BackupOnly");
//assertTrue("Search result not found.", results.numbersOfChildEntries() > 0);
}
public void testBackupExcluded() {
updateOmitSetting(true);
GroupVersioned results = mDb.search("BackupOnly");
//assertFalse("Search result found, but should not have been.", results.numbersOfChildEntries() > 0);
}
private void updateOmitSetting(boolean setting) {
Context ctx = getContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("settings_omitbackup_key", setting);
editor.commit();
}
private Database mDb;
@Override
protected void setUp() throws Exception {
super.setUp();
//mDb = TestData.GetDb1(getContext(), true);
}
public void testSearch() {
GroupVersioned results = mDb.search("Amazon");
//assertTrue("Search result not found.", results.numbersOfChildEntries() > 0);
}
public void testBackupIncluded() {
updateOmitSetting(false);
GroupVersioned results = mDb.search("BackupOnly");
//assertTrue("Search result not found.", results.numbersOfChildEntries() > 0);
}
public void testBackupExcluded() {
updateOmitSetting(true);
GroupVersioned results = mDb.search("BackupOnly");
//assertFalse("Search result found, but should not have been.", results.numbersOfChildEntries() > 0);
}
private void updateOmitSetting(boolean setting) {
Context ctx = getContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("settings_omitbackup_key", setting);
editor.commit();
}
}

View File

@@ -1,22 +1,22 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.tests.stream;
import static org.junit.Assert.assertArrayEquals;
@@ -34,77 +34,77 @@ import com.kunzisoft.keepass.stream.HashedBlockInputStream;
import com.kunzisoft.keepass.stream.HashedBlockOutputStream;
public class HashedBlock extends TestCase {
private static Random rand = new Random();
public void testBlockAligned() throws IOException {
testSize(1024, 1024);
}
public void testOffset() throws IOException {
testSize(1500, 1024);
}
private void testSize(int blockSize, int bufferSize) throws IOException {
byte[] orig = new byte[blockSize];
rand.nextBytes(orig);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
HashedBlockOutputStream output = new HashedBlockOutputStream(bos, bufferSize);
output.write(orig);
output.close();
byte[] encoded = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(encoded);
HashedBlockInputStream input = new HashedBlockInputStream(bis);
private static Random rand = new Random();
ByteArrayOutputStream decoded = new ByteArrayOutputStream();
while ( true ) {
byte[] buf = new byte[1024];
int read = input.read(buf);
if ( read == -1 ) {
break;
}
decoded.write(buf, 0, read);
}
byte[] out = decoded.toByteArray();
assertArrayEquals(orig, out);
}
public void testGZIPStream() throws IOException {
final int testLength = 32000;
byte[] orig = new byte[testLength];
rand.nextBytes(orig);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
HashedBlockOutputStream hos = new HashedBlockOutputStream(bos);
GZIPOutputStream zos = new GZIPOutputStream(hos);
zos.write(orig);
zos.close();
byte[] compressed = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(compressed);
HashedBlockInputStream his = new HashedBlockInputStream(bis);
GZIPInputStream zis = new GZIPInputStream(his);
byte[] uncompressed = new byte[testLength];
int read = 0;
while (read != -1 && testLength - read > 0) {
read += zis.read(uncompressed, read, testLength - read);
}
assertArrayEquals("Output not equal to input", orig, uncompressed);
}
public void testBlockAligned() throws IOException {
testSize(1024, 1024);
}
public void testOffset() throws IOException {
testSize(1500, 1024);
}
private void testSize(int blockSize, int bufferSize) throws IOException {
byte[] orig = new byte[blockSize];
rand.nextBytes(orig);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
HashedBlockOutputStream output = new HashedBlockOutputStream(bos, bufferSize);
output.write(orig);
output.close();
byte[] encoded = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(encoded);
HashedBlockInputStream input = new HashedBlockInputStream(bis);
ByteArrayOutputStream decoded = new ByteArrayOutputStream();
while ( true ) {
byte[] buf = new byte[1024];
int read = input.read(buf);
if ( read == -1 ) {
break;
}
decoded.write(buf, 0, read);
}
byte[] out = decoded.toByteArray();
assertArrayEquals(orig, out);
}
public void testGZIPStream() throws IOException {
final int testLength = 32000;
byte[] orig = new byte[testLength];
rand.nextBytes(orig);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
HashedBlockOutputStream hos = new HashedBlockOutputStream(bos);
GZIPOutputStream zos = new GZIPOutputStream(hos);
zos.write(orig);
zos.close();
byte[] compressed = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(compressed);
HashedBlockInputStream his = new HashedBlockInputStream(bis);
GZIPInputStream zis = new GZIPInputStream(his);
byte[] uncompressed = new byte[testLength];
int read = 0;
while (read != -1 && testLength - read > 0) {
read += zis.read(uncompressed, read, testLength - read);
}
assertArrayEquals("Output not equal to input", orig, uncompressed);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -30,28 +30,28 @@ public class StringUtilTest extends TestCase {
private final String search = "BcDe";
private final String badSearch = "Ed";
public void testIndexOfIgnoreCase1() {
assertEquals(1, StringUtil.INSTANCE.indexOfIgnoreCase(text, search, Locale.ENGLISH));
}
public void testIndexOfIgnoreCase1() {
assertEquals(1, StringUtil.INSTANCE.indexOfIgnoreCase(text, search, Locale.ENGLISH));
}
public void testIndexOfIgnoreCase2() {
assertEquals(-1, StringUtil.INSTANCE.indexOfIgnoreCase(text, search, Locale.ENGLISH), 2);
}
public void testIndexOfIgnoreCase2() {
assertEquals(-1, StringUtil.INSTANCE.indexOfIgnoreCase(text, search, Locale.ENGLISH), 2);
}
public void testIndexOfIgnoreCase3() {
assertEquals(-1, StringUtil.INSTANCE.indexOfIgnoreCase(text, badSearch, Locale.ENGLISH));
}
private final String repText = "AbCtestingaBc";
private final String repSearch = "ABc";
private final String repSearchBad = "CCCCCC";
private final String repNew = "12345";
private final String repResult = "12345testing12345";
public void testReplaceAllIgnoresCase1() {
assertEquals(repResult, StringUtil.INSTANCE.replaceAllIgnoresCase(repText, repSearch, repNew, Locale.ENGLISH));
}
public void testIndexOfIgnoreCase3() {
assertEquals(-1, StringUtil.INSTANCE.indexOfIgnoreCase(text, badSearch, Locale.ENGLISH));
}
public void testReplaceAllIgnoresCase2() {
assertEquals(repText, StringUtil.INSTANCE.replaceAllIgnoresCase(repText, repSearchBad, repNew, Locale.ENGLISH));
}
private final String repText = "AbCtestingaBc";
private final String repSearch = "ABc";
private final String repSearchBad = "CCCCCC";
private final String repNew = "12345";
private final String repResult = "12345testing12345";
public void testReplaceAllIgnoresCase1() {
assertEquals(repResult, StringUtil.INSTANCE.replaceAllIgnoresCase(repText, repSearch, repNew, Locale.ENGLISH));
}
public void testReplaceAllIgnoresCase2() {
assertEquals(repText, StringUtil.INSTANCE.replaceAllIgnoresCase(repText, repSearchBad, repNew, Locale.ENGLISH));
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -29,46 +29,46 @@ import com.kunzisoft.keepass.stylish.Stylish;
import java.util.Calendar;
public class App extends MultiDexApplication {
private static Database db = null;
private static Calendar calendar = null;
private static RecentFileHistory fileHistory = null;
public static Database getDB() {
if ( db == null ) {
db = new Database();
}
return db;
}
private static Database db = null;
private static Calendar calendar = null;
private static RecentFileHistory fileHistory = null;
public static RecentFileHistory getFileHistory() {
return fileHistory;
}
public static void setDB(Database d) {
db = d;
}
public static Database getDB() {
if ( db == null ) {
db = new Database();
}
return db;
}
public static Calendar getCalendar() {
if ( calendar == null ) {
calendar = Calendar.getInstance();
}
return calendar;
}
public static RecentFileHistory getFileHistory() {
return fileHistory;
}
@Override
public void onCreate() {
super.onCreate();
public static void setDB(Database d) {
db = d;
}
Stylish.init(this);
fileHistory = new RecentFileHistory(this);
PRNGFixes.apply();
}
public static Calendar getCalendar() {
if ( calendar == null ) {
calendar = Calendar.getInstance();
}
return calendar;
}
@Override
public void onTerminate() {
if ( db != null ) {
db.closeAndClear(getApplicationContext());
}
super.onTerminate();
}
@Override
public void onCreate() {
super.onCreate();
Stylish.init(this);
fileHistory = new RecentFileHistory(this);
PRNGFixes.apply();
}
@Override
public void onTerminate() {
if ( db != null ) {
db.closeAndClear(getApplicationContext());
}
super.onTerminate();
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -25,15 +25,15 @@ import android.app.backup.SharedPreferencesBackupHelper;
@SuppressLint("NewApi")
public class SettingsBackupAgent extends BackupAgentHelper {
private static final String PREFS_BACKUP_KEY = "prefs";
@Override
public void onCreate() {
String defaultPrefs = this.getPackageName() + "_preferences";
SharedPreferencesBackupHelper prefHelper = new SharedPreferencesBackupHelper(this, defaultPrefs);
addHelper(PREFS_BACKUP_KEY, prefHelper);
}
private static final String PREFS_BACKUP_KEY = "prefs";
@Override
public void onCreate() {
String defaultPrefs = this.getPackageName() + "_preferences";
SharedPreferencesBackupHelper prefHelper = new SharedPreferencesBackupHelper(this, defaultPrefs);
addHelper(PREFS_BACKUP_KEY, prefHelper);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -23,14 +23,14 @@ import java.security.Provider;
public final class AESProvider extends Provider {
/**
*
*/
private static final long serialVersionUID = -3846349284296062658L;
/**
*
*/
private static final long serialVersionUID = -3846349284296062658L;
public AESProvider() {
super("AESProvider", 1.0, "");
put("Cipher.AES",NativeAESCipherSpi.class.getName());
}
public AESProvider() {
super("AESProvider", 1.0, "");
put("Cipher.AES",NativeAESCipherSpi.class.getName());
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -38,58 +38,58 @@ import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
public class CipherFactory {
private static boolean blacklistInit = false;
private static boolean blacklisted;
private static boolean blacklistInit = false;
private static boolean blacklisted;
static {
Security.addProvider(new BouncyCastleProvider());
}
public static Cipher getInstance(String transformation) throws NoSuchAlgorithmException, NoSuchPaddingException {
return getInstance(transformation, false);
}
public static Cipher getInstance(String transformation, boolean androidOverride) throws NoSuchAlgorithmException, NoSuchPaddingException {
// Return the native AES if it is possible
if ( (!deviceBlacklisted()) && (!androidOverride) && hasNativeImplementation(transformation) && NativeLib.loaded() ) {
return Cipher.getInstance(transformation, new AESProvider());
} else {
static {
Security.addProvider(new BouncyCastleProvider());
}
public static Cipher getInstance(String transformation) throws NoSuchAlgorithmException, NoSuchPaddingException {
return getInstance(transformation, false);
}
public static Cipher getInstance(String transformation, boolean androidOverride) throws NoSuchAlgorithmException, NoSuchPaddingException {
// Return the native AES if it is possible
if ( (!deviceBlacklisted()) && (!androidOverride) && hasNativeImplementation(transformation) && NativeLib.loaded() ) {
return Cipher.getInstance(transformation, new AESProvider());
} else {
return Cipher.getInstance(transformation);
}
}
public static boolean deviceBlacklisted() {
if (!blacklistInit) {
blacklistInit = true;
// The Acer Iconia A500 is special and seems to always crash in the native crypto libraries
blacklisted = Build.MODEL.equals("A500");
}
return blacklisted;
}
private static boolean hasNativeImplementation(String transformation) {
return transformation.equals("AES/CBC/PKCS5Padding");
}
}
}
public static boolean deviceBlacklisted() {
if (!blacklistInit) {
blacklistInit = true;
// The Acer Iconia A500 is special and seems to always crash in the native crypto libraries
blacklisted = Build.MODEL.equals("A500");
}
return blacklisted;
}
private static boolean hasNativeImplementation(String transformation) {
return transformation.equals("AES/CBC/PKCS5Padding");
}
/** Generate appropriate cipher based on KeePass 2.x UUID's
* @param uuid
* @return
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
*/
public static CipherEngine getInstance(UUID uuid) throws NoSuchAlgorithmException {
if ( uuid.equals(AesEngine.CIPHER_UUID) ) {
return new AesEngine();
} else if ( uuid.equals(TwofishEngine.CIPHER_UUID) ) {
return new TwofishEngine();
} else if ( uuid.equals(ChaCha20Engine.CIPHER_UUID)) {
return new ChaCha20Engine();
}
throw new NoSuchAlgorithmException("UUID unrecognized.");
}
/** Generate appropriate cipher based on KeePass 2.x UUID's
* @param uuid
* @return
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
*/
public static CipherEngine getInstance(UUID uuid) throws NoSuchAlgorithmException {
if ( uuid.equals(AesEngine.CIPHER_UUID) ) {
return new AesEngine();
} else if ( uuid.equals(TwofishEngine.CIPHER_UUID) ) {
return new TwofishEngine();
} else if ( uuid.equals(ChaCha20Engine.CIPHER_UUID)) {
return new ChaCha20Engine();
}
throw new NoSuchAlgorithmException("UUID unrecognized.");
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -44,284 +44,284 @@ import javax.crypto.spec.IvParameterSpec;
public class NativeAESCipherSpi extends CipherSpi {
private static final String TAG = NativeAESCipherSpi.class.getName();
private static final String TAG = NativeAESCipherSpi.class.getName();
private static boolean mIsStaticInit = false;
private static HashMap<PhantomReference<NativeAESCipherSpi>, Long> mCleanup = new HashMap<PhantomReference<NativeAESCipherSpi>, Long>();
private static ReferenceQueue<NativeAESCipherSpi> mQueue = new ReferenceQueue<NativeAESCipherSpi>();
private final int AES_BLOCK_SIZE = 16;
private byte[] mIV;
private boolean mIsInited = false;
private boolean mEncrypting = false;
private long mCtxPtr;
private boolean mPadding = false;
private static void staticInit() {
mIsStaticInit = true;
// Start the cipher context cleanup thread to run forever
(new Thread(new Cleanup())).start();
}
private static void addToCleanupQueue(NativeAESCipherSpi ref, long ptr) {
Log.d(TAG, "queued cipher context: " + ptr);
mCleanup.put(new PhantomReference<NativeAESCipherSpi>(ref, mQueue), ptr);
}
/** Work with the garbage collector to clean up openssl memory when the cipher
* context is garbage collected.
* @author bpellin
*
*/
private static class Cleanup implements Runnable {
private static boolean mIsStaticInit = false;
private static HashMap<PhantomReference<NativeAESCipherSpi>, Long> mCleanup = new HashMap<PhantomReference<NativeAESCipherSpi>, Long>();
private static ReferenceQueue<NativeAESCipherSpi> mQueue = new ReferenceQueue<NativeAESCipherSpi>();
public void run() {
while (true) {
try {
Reference<? extends NativeAESCipherSpi> ref = mQueue.remove();
long ctx = mCleanup.remove(ref);
nCleanup(ctx);
Log.d(TAG, "Cleaned up cipher context: " + ctx);
} catch (InterruptedException e) {
// Do nothing, but resume looping if mQueue.remove is interrupted
}
}
}
}
private static native void nCleanup(long ctxPtr);
private final int AES_BLOCK_SIZE = 16;
private byte[] mIV;
public NativeAESCipherSpi() {
if ( ! mIsStaticInit ) {
staticInit();
}
}
@Override
protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException {
int maxSize = engineGetOutputSize(inputLen);
byte[] output = new byte[maxSize];
int finalSize;
try {
finalSize = doFinal(input, inputOffset, inputLen, output, 0);
} catch (ShortBufferException e) {
// This shouldn't be possible rethrow as RuntimeException
throw new RuntimeException("Short buffer exception shouldn't be possible from here.");
}
if ( maxSize == finalSize ) {
return output;
} else {
// TODO: Special doFinal to avoid this copy
byte[] exact = new byte[finalSize];
System.arraycopy(output, 0, exact, 0, finalSize);
return exact;
}
}
private boolean mIsInited = false;
private boolean mEncrypting = false;
private long mCtxPtr;
@Override
protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset) throws ShortBufferException,
IllegalBlockSizeException, BadPaddingException {
int result = doFinal(input, inputOffset, inputLen, output, outputOffset);
if ( result == -1 ) {
throw new ShortBufferException();
}
return result;
}
private int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)
throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
int outputSize = engineGetOutputSize(inputLen);
int updateAmt;
if (input != null && inputLen > 0) {
updateAmt = nUpdate(mCtxPtr, input, inputOffset, inputLen, output, outputOffset, outputSize);
} else {
updateAmt = 0;
}
int finalAmt = nFinal(mCtxPtr, mPadding, output, outputOffset + updateAmt, outputSize - updateAmt);
int out = updateAmt + finalAmt;
return out;
}
private native int nFinal(long ctxPtr, boolean usePadding, byte[] output, int outputOffest, int outputSize)
throws ShortBufferException, IllegalBlockSizeException, BadPaddingException;
private boolean mPadding = false;
@Override
protected int engineGetBlockSize() {
return AES_BLOCK_SIZE;
}
private static void staticInit() {
mIsStaticInit = true;
@Override
protected byte[] engineGetIV() {
byte[] copyIV = new byte[0];
if (mIV != null) {
int lengthIV = mIV.length;
copyIV = new byte[lengthIV];
System.arraycopy(mIV, 0, copyIV, 0, lengthIV);
}
return copyIV;
}
// Start the cipher context cleanup thread to run forever
(new Thread(new Cleanup())).start();
}
@Override
protected int engineGetOutputSize(int inputLen) {
return inputLen + nGetCacheSize(mCtxPtr) + AES_BLOCK_SIZE;
}
private native int nGetCacheSize(long ctxPtr);
private static void addToCleanupQueue(NativeAESCipherSpi ref, long ptr) {
Log.d(TAG, "queued cipher context: " + ptr);
mCleanup.put(new PhantomReference<NativeAESCipherSpi>(ref, mQueue), ptr);
}
@Override
protected AlgorithmParameters engineGetParameters() {
// TODO Auto-generated method stub
return null;
}
/** Work with the garbage collector to clean up openssl memory when the cipher
* context is garbage collected.
* @author bpellin
*
*/
private static class Cleanup implements Runnable {
@Override
protected void engineInit(int opmode, Key key, SecureRandom random)
throws InvalidKeyException {
public void run() {
while (true) {
try {
Reference<? extends NativeAESCipherSpi> ref = mQueue.remove();
byte[] ivArray = new byte[16];
random.nextBytes(ivArray);
init(opmode, key, new IvParameterSpec(ivArray));
}
long ctx = mCleanup.remove(ref);
nCleanup(ctx);
Log.d(TAG, "Cleaned up cipher context: " + ctx);
@Override
protected void engineInit(int opmode, Key key,
AlgorithmParameterSpec params, SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
IvParameterSpec ivparam;
if ( params instanceof IvParameterSpec ) {
ivparam = (IvParameterSpec) params;
} else {
throw new InvalidAlgorithmParameterException("params must be an IvParameterSpec.");
}
init(opmode, key, ivparam);
}
} catch (InterruptedException e) {
// Do nothing, but resume looping if mQueue.remove is interrupted
}
}
}
@Override
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
SecureRandom random) throws InvalidKeyException,
InvalidAlgorithmParameterException {
try {
engineInit(opmode, key, params.getParameterSpec(AlgorithmParameterSpec.class), random);
} catch (InvalidParameterSpecException e) {
throw new InvalidAlgorithmParameterException(e);
}
}
}
private static native void nCleanup(long ctxPtr);
private void init(int opmode, Key key, IvParameterSpec params) {
if ( mIsInited ) {
// Do not allow multiple inits
assert(true);
throw new RuntimeException("Don't allow multiple inits");
} else {
NativeLib.init();
mIsInited = true;
}
mIV = params.getIV();
mEncrypting = opmode == Cipher.ENCRYPT_MODE;
mCtxPtr = nInit(mEncrypting, key.getEncoded(), mIV);
addToCleanupQueue(this, mCtxPtr);
}
private native long nInit(boolean encrypting, byte[] key, byte[] iv);
@Override
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
if ( ! mode.equals("CBC") ) {
throw new NoSuchAlgorithmException("This only supports CBC mode");
}
}
public NativeAESCipherSpi() {
if ( ! mIsStaticInit ) {
staticInit();
}
}
@Override
protected void engineSetPadding(String padding)
throws NoSuchPaddingException {
if ( ! mIsInited ) {
NativeLib.init();
}
if ( padding.length() == 0 ) {
return;
}
@Override
protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException {
int maxSize = engineGetOutputSize(inputLen);
byte[] output = new byte[maxSize];
if ( ! padding.equals("PKCS5Padding") ) {
throw new NoSuchPaddingException("Only supports PKCS5Padding.");
}
mPadding = true;
}
@Override
protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
int maxSize = engineGetOutputSize(inputLen);
byte output[] = new byte[maxSize];
int updateSize = update(input, inputOffset, inputLen, output, 0);
if ( updateSize == maxSize ) {
return output;
} else {
// TODO: We could optimize update for this case to avoid this extra copy
byte[] exact = new byte[updateSize];
System.arraycopy(output, 0, exact, 0, updateSize);
return exact;
}
}
int finalSize;
try {
finalSize = doFinal(input, inputOffset, inputLen, output, 0);
} catch (ShortBufferException e) {
// This shouldn't be possible rethrow as RuntimeException
throw new RuntimeException("Short buffer exception shouldn't be possible from here.");
}
if ( maxSize == finalSize ) {
return output;
} else {
// TODO: Special doFinal to avoid this copy
byte[] exact = new byte[finalSize];
System.arraycopy(output, 0, exact, 0, finalSize);
return exact;
}
}
@Override
protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset) throws ShortBufferException,
IllegalBlockSizeException, BadPaddingException {
int result = doFinal(input, inputOffset, inputLen, output, outputOffset);
if ( result == -1 ) {
throw new ShortBufferException();
}
return result;
}
private int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)
throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
int outputSize = engineGetOutputSize(inputLen);
int updateAmt;
if (input != null && inputLen > 0) {
updateAmt = nUpdate(mCtxPtr, input, inputOffset, inputLen, output, outputOffset, outputSize);
} else {
updateAmt = 0;
}
int finalAmt = nFinal(mCtxPtr, mPadding, output, outputOffset + updateAmt, outputSize - updateAmt);
int out = updateAmt + finalAmt;
return out;
}
private native int nFinal(long ctxPtr, boolean usePadding, byte[] output, int outputOffest, int outputSize)
throws ShortBufferException, IllegalBlockSizeException, BadPaddingException;
@Override
protected int engineGetBlockSize() {
return AES_BLOCK_SIZE;
}
@Override
protected byte[] engineGetIV() {
byte[] copyIV = new byte[0];
if (mIV != null) {
int lengthIV = mIV.length;
copyIV = new byte[lengthIV];
System.arraycopy(mIV, 0, copyIV, 0, lengthIV);
}
return copyIV;
}
@Override
protected int engineGetOutputSize(int inputLen) {
return inputLen + nGetCacheSize(mCtxPtr) + AES_BLOCK_SIZE;
}
private native int nGetCacheSize(long ctxPtr);
@Override
protected AlgorithmParameters engineGetParameters() {
// TODO Auto-generated method stub
return null;
}
@Override
protected void engineInit(int opmode, Key key, SecureRandom random)
throws InvalidKeyException {
byte[] ivArray = new byte[16];
random.nextBytes(ivArray);
init(opmode, key, new IvParameterSpec(ivArray));
}
@Override
protected void engineInit(int opmode, Key key,
AlgorithmParameterSpec params, SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
IvParameterSpec ivparam;
if ( params instanceof IvParameterSpec ) {
ivparam = (IvParameterSpec) params;
} else {
throw new InvalidAlgorithmParameterException("params must be an IvParameterSpec.");
}
init(opmode, key, ivparam);
}
@Override
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
SecureRandom random) throws InvalidKeyException,
InvalidAlgorithmParameterException {
try {
engineInit(opmode, key, params.getParameterSpec(AlgorithmParameterSpec.class), random);
} catch (InvalidParameterSpecException e) {
throw new InvalidAlgorithmParameterException(e);
}
}
private void init(int opmode, Key key, IvParameterSpec params) {
if ( mIsInited ) {
// Do not allow multiple inits
assert(true);
throw new RuntimeException("Don't allow multiple inits");
} else {
NativeLib.init();
mIsInited = true;
}
mIV = params.getIV();
mEncrypting = opmode == Cipher.ENCRYPT_MODE;
mCtxPtr = nInit(mEncrypting, key.getEncoded(), mIV);
addToCleanupQueue(this, mCtxPtr);
}
private native long nInit(boolean encrypting, byte[] key, byte[] iv);
@Override
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
if ( ! mode.equals("CBC") ) {
throw new NoSuchAlgorithmException("This only supports CBC mode");
}
}
@Override
protected void engineSetPadding(String padding)
throws NoSuchPaddingException {
if ( ! mIsInited ) {
NativeLib.init();
}
if ( padding.length() == 0 ) {
return;
}
if ( ! padding.equals("PKCS5Padding") ) {
throw new NoSuchPaddingException("Only supports PKCS5Padding.");
}
mPadding = true;
}
@Override
protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
int maxSize = engineGetOutputSize(inputLen);
byte output[] = new byte[maxSize];
int updateSize = update(input, inputOffset, inputLen, output, 0);
if ( updateSize == maxSize ) {
return output;
} else {
// TODO: We could optimize update for this case to avoid this extra copy
byte[] exact = new byte[updateSize];
System.arraycopy(output, 0, exact, 0, updateSize);
return exact;
}
}
@Override
protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset) throws ShortBufferException {
int result = update(input, inputOffset, inputLen, output, outputOffset);
if ( result == -1 ) {
throw new ShortBufferException("Insufficient buffer.");
}
return result;
}
int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) {
int outputSize = engineGetOutputSize(inputLen);
int out = nUpdate(mCtxPtr, input, inputOffset, inputLen, output, outputOffset, outputSize);
return out;
}
private native int nUpdate(long ctxPtr, byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset, int outputSize);
@Override
protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset) throws ShortBufferException {
int result = update(input, inputOffset, inputLen, output, outputOffset);
if ( result == -1 ) {
throw new ShortBufferException("Insufficient buffer.");
}
return result;
}
int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) {
int outputSize = engineGetOutputSize(inputLen);
int out = nUpdate(mCtxPtr, input, inputOffset, inputLen, output, outputOffset, outputSize);
return out;
}
private native int nUpdate(long ctxPtr, byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset, int outputSize);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -20,27 +20,27 @@
package com.kunzisoft.keepass.crypto;
public class NativeLib {
private static boolean isLoaded = false;
private static boolean loadSuccess = false;
public static boolean loaded() {
return init();
}
public static boolean init() {
if ( ! isLoaded ) {
try {
System.loadLibrary("final-key");
System.loadLibrary("argon2");
} catch ( UnsatisfiedLinkError e) {
return false;
}
isLoaded = true;
loadSuccess = true;
}
return loadSuccess;
}
private static boolean isLoaded = false;
private static boolean loadSuccess = false;
public static boolean loaded() {
return init();
}
public static boolean init() {
if ( ! isLoaded ) {
try {
System.loadLibrary("final-key");
System.loadLibrary("argon2");
} catch ( UnsatisfiedLinkError e) {
return false;
}
isLoaded = true;
loadSuccess = true;
}
return loadSuccess;
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -26,48 +26,48 @@ import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
public class PwStreamCipherFactory {
public static StreamCipher getInstance(CrsAlgorithm alg, byte[] key) {
if ( alg == CrsAlgorithm.Salsa20 ) {
return getSalsa20(key);
} else if (alg == CrsAlgorithm.ChaCha20) {
return getChaCha20(key);
} else {
return null;
}
}
private static final byte[] SALSA_IV = new byte[]{ (byte)0xE8, 0x30, 0x09, 0x4B,
public static StreamCipher getInstance(CrsAlgorithm alg, byte[] key) {
if ( alg == CrsAlgorithm.Salsa20 ) {
return getSalsa20(key);
} else if (alg == CrsAlgorithm.ChaCha20) {
return getChaCha20(key);
} else {
return null;
}
}
private static final byte[] SALSA_IV = new byte[]{ (byte)0xE8, 0x30, 0x09, 0x4B,
(byte)0x97, 0x20, 0x5D, 0x2A };
private static StreamCipher getSalsa20(byte[] key) {
// Build stream cipher key
byte[] key32 = CryptoUtil.hashSha256(key);
private static StreamCipher getSalsa20(byte[] key) {
// Build stream cipher key
byte[] key32 = CryptoUtil.hashSha256(key);
KeyParameter keyParam = new KeyParameter(key32);
ParametersWithIV ivParam = new ParametersWithIV(keyParam, SALSA_IV);
KeyParameter keyParam = new KeyParameter(key32);
ParametersWithIV ivParam = new ParametersWithIV(keyParam, SALSA_IV);
StreamCipher cipher = new Salsa20Engine();
cipher.init(true, ivParam);
StreamCipher cipher = new Salsa20Engine();
cipher.init(true, ivParam);
return cipher;
}
return cipher;
}
private static StreamCipher getChaCha20(byte[] key) {
// Build stream cipher key
byte[] hash = CryptoUtil.hashSha512(key);
byte[] key32 = new byte[32];
byte[] iv = new byte[12];
private static StreamCipher getChaCha20(byte[] key) {
// Build stream cipher key
byte[] hash = CryptoUtil.hashSha512(key);
byte[] key32 = new byte[32];
byte[] iv = new byte[12];
System.arraycopy(hash, 0, key32, 0, 32);
System.arraycopy(hash, 0, key32, 0, 32);
System.arraycopy(hash, 32, iv, 0, 12);
KeyParameter keyParam = new KeyParameter(key32);
ParametersWithIV ivParam = new ParametersWithIV(keyParam, iv);
KeyParameter keyParam = new KeyParameter(key32);
ParametersWithIV ivParam = new ParametersWithIV(keyParam, iv);
StreamCipher cipher = new ChaCha7539Engine();
cipher.init(true, ivParam);
return cipher;
}
cipher.init(true, ivParam);
return cipher;
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -31,48 +31,48 @@ import javax.crypto.spec.SecretKeySpec;
public class AndroidFinalKey extends FinalKey {
@Override
public byte[] transformMasterKey(byte[] pKeySeed, byte[] pKey, long rounds) throws IOException {
Cipher cipher;
try {
cipher = Cipher.getInstance("AES/ECB/NoPadding");
} catch (NoSuchAlgorithmException e) {
throw new IOException("NoSuchAlgorithm: " + e.getMessage());
} catch (NoSuchPaddingException e) {
throw new IOException("NoSuchPadding: " + e.getMessage());
}
@Override
public byte[] transformMasterKey(byte[] pKeySeed, byte[] pKey, long rounds) throws IOException {
Cipher cipher;
try {
cipher = Cipher.getInstance("AES/ECB/NoPadding");
} catch (NoSuchAlgorithmException e) {
throw new IOException("NoSuchAlgorithm: " + e.getMessage());
} catch (NoSuchPaddingException e) {
throw new IOException("NoSuchPadding: " + e.getMessage());
}
try {
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(pKeySeed, "AES"));
} catch (InvalidKeyException e) {
throw new IOException("InvalidPasswordException: " + e.getMessage());
}
try {
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(pKeySeed, "AES"));
} catch (InvalidKeyException e) {
throw new IOException("InvalidPasswordException: " + e.getMessage());
}
// Encrypt key rounds times
byte[] newKey = new byte[pKey.length];
System.arraycopy(pKey, 0, newKey, 0, pKey.length);
byte[] destKey = new byte[pKey.length];
for (int i = 0; i < rounds; i++) {
try {
cipher.update(newKey, 0, newKey.length, destKey, 0);
System.arraycopy(destKey, 0, newKey, 0, newKey.length);
// Encrypt key rounds times
byte[] newKey = new byte[pKey.length];
System.arraycopy(pKey, 0, newKey, 0, pKey.length);
byte[] destKey = new byte[pKey.length];
for (int i = 0; i < rounds; i++) {
try {
cipher.update(newKey, 0, newKey.length, destKey, 0);
System.arraycopy(destKey, 0, newKey, 0, newKey.length);
} catch (ShortBufferException e) {
throw new IOException("Short buffer: " + e.getMessage());
}
}
} catch (ShortBufferException e) {
throw new IOException("Short buffer: " + e.getMessage());
}
}
// Hash the key
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
assert true;
throw new IOException("SHA-256 not implemented here: " + e.getMessage());
}
// Hash the key
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
assert true;
throw new IOException("SHA-256 not implemented here: " + e.getMessage());
}
md.update(newKey);
return md.digest();
}
md.update(newKey);
return md.digest();
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -22,5 +22,5 @@ package com.kunzisoft.keepass.crypto.finalkey;
import java.io.IOException;
public abstract class FinalKey {
public abstract byte[] transformMasterKey(byte[] seed, byte[] key, long rounds) throws IOException;
public abstract byte[] transformMasterKey(byte[] seed, byte[] key, long rounds) throws IOException;
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -22,17 +22,17 @@ package com.kunzisoft.keepass.crypto.finalkey;
import com.kunzisoft.keepass.crypto.CipherFactory;
public class FinalKeyFactory {
public static FinalKey createFinalKey() {
return createFinalKey(false);
}
public static FinalKey createFinalKey(boolean androidOverride) {
// Prefer the native final key implementation
if ( !CipherFactory.deviceBlacklisted() && !androidOverride && NativeFinalKey.availble() ) {
return new NativeFinalKey();
} else {
// Fall back on the android crypto implementation
return new AndroidFinalKey();
}
}
public static FinalKey createFinalKey() {
return createFinalKey(false);
}
public static FinalKey createFinalKey(boolean androidOverride) {
// Prefer the native final key implementation
if ( !CipherFactory.deviceBlacklisted() && !androidOverride && NativeFinalKey.availble() ) {
return new NativeFinalKey();
} else {
// Fall back on the android crypto implementation
return new AndroidFinalKey();
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -25,22 +25,22 @@ import java.io.IOException;
public class NativeFinalKey extends FinalKey {
public static boolean availble() {
return NativeLib.init();
}
@Override
public byte[] transformMasterKey(byte[] seed, byte[] key, long rounds) throws IOException {
NativeLib.init();
return nTransformMasterKey(seed, key, rounds);
public static boolean availble() {
return NativeLib.init();
}
}
private static native byte[] nTransformMasterKey(byte[] seed, byte[] key, long rounds);
@Override
public byte[] transformMasterKey(byte[] seed, byte[] key, long rounds) throws IOException {
NativeLib.init();
// For testing
return nTransformMasterKey(seed, key, rounds);
}
private static native byte[] nTransformMasterKey(byte[] seed, byte[] key, long rounds);
// For testing
/*
public static byte[] reflect(byte[] key) {
NativeLib.init();
@@ -50,6 +50,6 @@ public class NativeFinalKey extends FinalKey {
private static native byte[] nativeReflect(byte[] key);
*/
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -39,126 +39,126 @@ import java.util.*;
*/
public class PwDatabaseV3 extends PwDatabase<PwGroupV3, PwEntryV3> {
private static final int DEFAULT_ENCRYPTION_ROUNDS = 300;
private static final int DEFAULT_ENCRYPTION_ROUNDS = 300;
private int numKeyEncRounds;
private int numKeyEncRounds;
protected PwGroupV3 rootGroup;
protected PwGroupV3 rootGroup;
public PwDatabaseV3() {
algorithm = PwEncryptionAlgorithm.AESRijndael;
numKeyEncRounds = DEFAULT_ENCRYPTION_ROUNDS;
}
@Override
public String getVersion() {
return "KeePass 1";
}
@Override
public String getVersion() {
return "KeePass 1";
}
@Override
public List<PwEncryptionAlgorithm> getAvailableEncryptionAlgorithms() {
List<PwEncryptionAlgorithm> list = new ArrayList<>();
list.add(PwEncryptionAlgorithm.AESRijndael);
return list;
}
@Override
public List<PwEncryptionAlgorithm> getAvailableEncryptionAlgorithms() {
List<PwEncryptionAlgorithm> list = new ArrayList<>();
list.add(PwEncryptionAlgorithm.AESRijndael);
return list;
}
public List<PwGroupV3> getRootGroups() {
public List<PwGroupV3> getRootGroups() {
List<PwGroupV3> kids = new ArrayList<>();
for (Map.Entry<PwNodeId, PwGroupV3> group : groupIndexes.entrySet()) {
if (group.getValue().getLevel() == 0)
kids.add(group.getValue());
}
return kids;
}
for (Map.Entry<PwNodeId, PwGroupV3> group : groupIndexes.entrySet()) {
if (group.getValue().getLevel() == 0)
kids.add(group.getValue());
}
return kids;
}
private void assignGroupsChildren(PwGroupV3 parent) {
int levelToCheck = parent.getLevel() + 1;
boolean startFromParentPosition = false;
for (PwGroupV3 groupToCheck: getGroupIndexes()) {
if (getRootGroup().getNodeId().equals(parent.getNodeId())
|| groupToCheck.getNodeId().equals(parent.getNodeId())) {
startFromParentPosition = true;
}
if (startFromParentPosition) {
if (groupToCheck.getLevel() < levelToCheck)
break;
else if (groupToCheck.getLevel() == levelToCheck)
parent.addChildGroup(groupToCheck);
}
}
}
private void assignGroupsChildren(PwGroupV3 parent) {
int levelToCheck = parent.getLevel() + 1;
boolean startFromParentPosition = false;
for (PwGroupV3 groupToCheck: getGroupIndexes()) {
if (getRootGroup().getNodeId().equals(parent.getNodeId())
|| groupToCheck.getNodeId().equals(parent.getNodeId())) {
startFromParentPosition = true;
}
if (startFromParentPosition) {
if (groupToCheck.getLevel() < levelToCheck)
break;
else if (groupToCheck.getLevel() == levelToCheck)
parent.addChildGroup(groupToCheck);
}
}
}
private void assignEntriesChildren(PwGroupV3 parent) {
for (PwEntryV3 entry : getEntryIndexes()) {
if (entry.getParent().getNodeId().equals(parent.getNodeId()))
parent.addChildEntry(entry);
}
}
private void assignEntriesChildren(PwGroupV3 parent) {
for (PwEntryV3 entry : getEntryIndexes()) {
if (entry.getParent().getNodeId().equals(parent.getNodeId()))
parent.addChildEntry(entry);
}
}
private void constructTreeFromIndex(PwGroupV3 currentGroup) {
private void constructTreeFromIndex(PwGroupV3 currentGroup) {
assignGroupsChildren(currentGroup);
assignEntriesChildren(currentGroup);
assignGroupsChildren(currentGroup);
assignEntriesChildren(currentGroup);
// set parent in child entries (normally useless but to be sure or to update parent metadata)
for (PwEntryV3 childEntry : currentGroup.getChildEntries()) {
childEntry.setParent(currentGroup);
}
// recursively construct child groups
for (PwGroupV3 childGroup : currentGroup.getChildGroups()) {
childGroup.setParent(currentGroup);
constructTreeFromIndex(childGroup);
}
}
// set parent in child entries (normally useless but to be sure or to update parent metadata)
for (PwEntryV3 childEntry : currentGroup.getChildEntries()) {
childEntry.setParent(currentGroup);
}
// recursively construct child groups
for (PwGroupV3 childGroup : currentGroup.getChildGroups()) {
childGroup.setParent(currentGroup);
constructTreeFromIndex(childGroup);
}
}
public void constructTreeFromIndex() {
constructTreeFromIndex(getRootGroup());
}
public void constructTreeFromIndex() {
constructTreeFromIndex(getRootGroup());
}
/**
* Generates an unused random tree id
*
* @return new tree id
*/
@Override
public PwNodeIdInt newGroupId() {
PwNodeIdInt newId;
do {
newId = new PwNodeIdInt();
} while (isGroupIdUsed(newId));
/**
* Generates an unused random tree id
*
* @return new tree id
*/
@Override
public PwNodeIdInt newGroupId() {
PwNodeIdInt newId;
do {
newId = new PwNodeIdInt();
} while (isGroupIdUsed(newId));
return newId;
}
return newId;
}
/**
* Generates an unused random tree id
*
* @return new tree id
*/
@Override
public PwNodeIdUUID newEntryId() {
PwNodeIdUUID newId;
do {
newId = new PwNodeIdUUID();
} while (isEntryIdUsed(newId));
/**
* Generates an unused random tree id
*
* @return new tree id
*/
@Override
public PwNodeIdUUID newEntryId() {
PwNodeIdUUID newId;
do {
newId = new PwNodeIdUUID();
} while (isEntryIdUsed(newId));
return newId;
}
return newId;
}
@Override
public byte[] getMasterKey(@Nullable String key, @Nullable InputStream keyInputStream)
throws InvalidKeyFileException, IOException {
@Override
public byte[] getMasterKey(@Nullable String key, @Nullable InputStream keyInputStream)
throws InvalidKeyFileException, IOException {
if (key != null && keyInputStream != null) {
return getCompositeKey(key, keyInputStream);
} else if (key != null) { // key.length() >= 0
return getPasswordKey(key);
} else if (keyInputStream != null) { // key == null
return getFileKey(keyInputStream);
} else {
throw new IllegalArgumentException("Key cannot be empty.");
}
}
if (key != null && keyInputStream != null) {
return getCompositeKey(key, keyInputStream);
} else if (key != null) { // key.length() >= 0
return getPasswordKey(key);
} else if (keyInputStream != null) { // key == null
return getFileKey(keyInputStream);
} else {
throw new IllegalArgumentException("Key cannot be empty.");
}
}
/**
* Encrypt the master key a few times to make brute-force key-search harder
@@ -170,84 +170,84 @@ public class PwDatabaseV3 extends PwDatabase<PwGroupV3, PwEntryV3> {
return key.transformMasterKey(pKeySeed, pKey, rounds);
}
public void makeFinalKey(byte[] masterSeed, byte[] masterSeed2, long numRounds) throws IOException {
public void makeFinalKey(byte[] masterSeed, byte[] masterSeed2, long numRounds) throws IOException {
// Write checksum Checksum
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new IOException("SHA-256 not implemented here.");
}
NullOutputStream nos = new NullOutputStream();
DigestOutputStream dos = new DigestOutputStream(nos, md);
// Write checksum Checksum
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new IOException("SHA-256 not implemented here.");
}
NullOutputStream nos = new NullOutputStream();
DigestOutputStream dos = new DigestOutputStream(nos, md);
byte[] transformedMasterKey = transformMasterKey(masterSeed2, masterKey, numRounds);
dos.write(masterSeed);
dos.write(transformedMasterKey);
byte[] transformedMasterKey = transformMasterKey(masterSeed2, masterKey, numRounds);
dos.write(masterSeed);
dos.write(transformedMasterKey);
finalKey = md.digest();
}
finalKey = md.digest();
}
@Override
protected String getPasswordEncoding() {
return "ISO-8859-1";
}
@Override
protected byte[] loadXmlKeyFile(InputStream keyInputStream) {
return null;
}
@Override
protected String getPasswordEncoding() {
return "ISO-8859-1";
}
@Override
protected byte[] loadXmlKeyFile(InputStream keyInputStream) {
return null;
}
@Override
public long getNumberKeyEncryptionRounds() {
return numKeyEncRounds;
}
@Override
public long getNumberKeyEncryptionRounds() {
return numKeyEncRounds;
}
@Override
public void setNumberKeyEncryptionRounds(long rounds) throws NumberFormatException {
if (rounds > Integer.MAX_VALUE || rounds < Integer.MIN_VALUE) {
throw new NumberFormatException();
}
numKeyEncRounds = (int) rounds;
}
@Override
public void setNumberKeyEncryptionRounds(long rounds) throws NumberFormatException {
if (rounds > Integer.MAX_VALUE || rounds < Integer.MIN_VALUE) {
throw new NumberFormatException();
}
numKeyEncRounds = (int) rounds;
}
@Override
public PwGroupV3 createGroup() {
return new PwGroupV3();
}
@Override
public PwGroupV3 createGroup() {
return new PwGroupV3();
}
public void setRootGroup(PwGroupV3 rootGroup) {
this.rootGroup = rootGroup;
}
public void setRootGroup(PwGroupV3 rootGroup) {
this.rootGroup = rootGroup;
}
@Override
public PwGroupV3 getRootGroup() {
return rootGroup;
}
@Override
public PwGroupV3 getRootGroup() {
return rootGroup;
}
@Override
public PwEntryV3 createEntry() {
return new PwEntryV3();
}
@Override
public PwEntryV3 createEntry() {
return new PwEntryV3();
}
@Override
public boolean isBackup(PwGroupV3 group) {
while (group != null) {
if (group.getLevel() == 0 && group.getTitle().equalsIgnoreCase("Backup")) {
return true;
}
group = group.getParent();
}
return false;
}
@Override
public boolean isBackup(PwGroupV3 group) {
while (group != null) {
if (group.getLevel() == 0 && group.getTitle().equalsIgnoreCase("Backup")) {
return true;
}
group = group.getParent();
}
return false;
}
@Override
public boolean isGroupSearchable(PwGroupV3 group, boolean omitBackup) {
if (!super.isGroupSearchable(group, omitBackup)) {
return false;
}
return !(omitBackup && isBackup(group));
}
@Override
public boolean isGroupSearchable(PwGroupV3 group, boolean omitBackup) {
if (!super.isGroupSearchable(group, omitBackup)) {
return false;
}
return !(omitBackup && isBackup(group));
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -37,11 +37,11 @@ import java.util.Date;
*/
public class PwDate implements Parcelable {
private static final int DATE_SIZE = 5;
private static final int DATE_SIZE = 5;
private Date jDate = null;
private boolean jDateBuilt = false;
transient private byte[] cDate = null;
private boolean jDateBuilt = false;
transient private byte[] cDate = null;
transient private boolean cDateBuilt = false;
public static final Date NEVER_EXPIRE = getNeverExpire();
@@ -73,47 +73,47 @@ public class PwDate implements Parcelable {
return cal.getTime();
}
public PwDate(byte[] buf, int offset) {
cDate = new byte[DATE_SIZE];
System.arraycopy(buf, offset, cDate, 0, DATE_SIZE);
cDateBuilt = true;
}
public PwDate(PwDate source) {
if (source.jDate != null) {
this.jDate = new Date(source.jDate.getTime());
}
this.jDateBuilt = source.jDateBuilt;
public PwDate(byte[] buf, int offset) {
cDate = new byte[DATE_SIZE];
System.arraycopy(buf, offset, cDate, 0, DATE_SIZE);
cDateBuilt = true;
}
if (source.cDate != null) {
int dateLength = source.cDate.length;
this.cDate = new byte[dateLength];
System.arraycopy(source.cDate, 0, this.cDate, 0, dateLength);
}
this.cDateBuilt = source.cDateBuilt;
}
public PwDate(PwDate source) {
if (source.jDate != null) {
this.jDate = new Date(source.jDate.getTime());
}
this.jDateBuilt = source.jDateBuilt;
public PwDate(Date date) {
jDate = new Date(date.getTime());
jDateBuilt = true;
}
public PwDate(long millis) {
jDate = new Date(millis);
jDateBuilt = true;
}
public PwDate() {
jDate = new Date();
jDateBuilt = true;
}
if (source.cDate != null) {
int dateLength = source.cDate.length;
this.cDate = new byte[dateLength];
System.arraycopy(source.cDate, 0, this.cDate, 0, dateLength);
}
this.cDateBuilt = source.cDateBuilt;
}
protected PwDate(Parcel in) {
jDate = (Date) in.readSerializable();
jDateBuilt = in.readByte() != 0;
public PwDate(Date date) {
jDate = new Date(date.getTime());
jDateBuilt = true;
}
public PwDate(long millis) {
jDate = new Date(millis);
jDateBuilt = true;
}
public PwDate() {
jDate = new Date();
jDateBuilt = true;
}
protected PwDate(Parcel in) {
jDate = (Date) in.readSerializable();
jDateBuilt = in.readByte() != 0;
cDateBuilt = false;
}
}
@Override
public int describeContents() {
@@ -121,146 +121,146 @@ public class PwDate implements Parcelable {
}
@Override
public void writeToParcel(Parcel dest, int flags) {
public void writeToParcel(Parcel dest, int flags) {
dest.writeSerializable(getDate());
dest.writeByte((byte) (jDateBuilt ? 1 : 0));
}
}
public static final Creator<PwDate> CREATOR = new Creator<PwDate>() {
@Override
public PwDate createFromParcel(Parcel in) {
return new PwDate(in);
}
public static final Creator<PwDate> CREATOR = new Creator<PwDate>() {
@Override
public PwDate createFromParcel(Parcel in) {
return new PwDate(in);
}
@Override
public PwDate[] newArray(int size) {
return new PwDate[size];
}
};
@Override
public PwDate[] newArray(int size) {
return new PwDate[size];
}
};
public Date getDate() {
if ( ! jDateBuilt ) {
jDate = readTime(cDate, 0, App.getCalendar());
jDateBuilt = true;
}
return jDate;
}
public byte[] getCDate() {
if ( ! cDateBuilt ) {
cDate = writeTime(jDate, App.getCalendar());
cDateBuilt = true;
}
return cDate;
}
/**
* Unpack date from 5 byte format. The five bytes at 'offset' are unpacked
* to a java.util.Date instance.
*/
public static Date readTime(byte[] buf, int offset, Calendar time) {
int dw1 = Types.readUByte(buf, offset);
int dw2 = Types.readUByte(buf, offset + 1);
int dw3 = Types.readUByte(buf, offset + 2);
int dw4 = Types.readUByte(buf, offset + 3);
int dw5 = Types.readUByte(buf, offset + 4);
public Date getDate() {
if ( ! jDateBuilt ) {
jDate = readTime(cDate, 0, App.getCalendar());
jDateBuilt = true;
}
// Unpack 5 byte structure to date and time
int year = (dw1 << 6) | (dw2 >> 2);
int month = ((dw2 & 0x00000003) << 2) | (dw3 >> 6);
return jDate;
}
int day = (dw3 >> 1) & 0x0000001F;
int hour = ((dw3 & 0x00000001) << 4) | (dw4 >> 4);
int minute = ((dw4 & 0x0000000F) << 2) | (dw5 >> 6);
int second = dw5 & 0x0000003F;
public byte[] getCDate() {
if ( ! cDateBuilt ) {
cDate = writeTime(jDate, App.getCalendar());
cDateBuilt = true;
}
if (time == null) {
time = Calendar.getInstance();
}
// File format is a 1 based month, java Calendar uses a zero based month
// File format is a 1 based day, java Calendar uses a 1 based day
time.set(year, month - 1, day, hour, minute, second);
return cDate;
}
return time.getTime();
/**
* Unpack date from 5 byte format. The five bytes at 'offset' are unpacked
* to a java.util.Date instance.
*/
public static Date readTime(byte[] buf, int offset, Calendar time) {
int dw1 = Types.readUByte(buf, offset);
int dw2 = Types.readUByte(buf, offset + 1);
int dw3 = Types.readUByte(buf, offset + 2);
int dw4 = Types.readUByte(buf, offset + 3);
int dw5 = Types.readUByte(buf, offset + 4);
}
// Unpack 5 byte structure to date and time
int year = (dw1 << 6) | (dw2 >> 2);
int month = ((dw2 & 0x00000003) << 2) | (dw3 >> 6);
public static byte[] writeTime(Date date) {
return writeTime(date, null);
}
public static byte[] writeTime(Date date, Calendar cal) {
if (date == null) {
return null;
}
int day = (dw3 >> 1) & 0x0000001F;
int hour = ((dw3 & 0x00000001) << 4) | (dw4 >> 4);
int minute = ((dw4 & 0x0000000F) << 2) | (dw5 >> 6);
int second = dw5 & 0x0000003F;
byte[] buf = new byte[5];
if (cal == null) {
cal = Calendar.getInstance();
}
cal.setTime(date);
if (time == null) {
time = Calendar.getInstance();
}
// File format is a 1 based month, java Calendar uses a zero based month
// File format is a 1 based day, java Calendar uses a 1 based day
time.set(year, month - 1, day, hour, minute, second);
int year = cal.get(Calendar.YEAR);
// File format is a 1 based month, java Calendar uses a zero based month
int month = cal.get(Calendar.MONTH) + 1;
// File format is a 0 based day, java Calendar uses a 1 based day
int day = cal.get(Calendar.DAY_OF_MONTH) - 1;
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
return time.getTime();
buf[0] = Types.writeUByte(((year >> 6) & 0x0000003F));
buf[1] = Types.writeUByte(((year & 0x0000003F) << 2)
| ((month >> 2) & 0x00000003));
buf[2] = (byte) (((month & 0x00000003) << 6)
| ((day & 0x0000001F) << 1) | ((hour >> 4) & 0x00000001));
buf[3] = (byte) (((hour & 0x0000000F) << 4) | ((minute >> 2) & 0x0000000F));
buf[4] = (byte) (((minute & 0x00000003) << 6) | (second & 0x0000003F));
}
return buf;
}
public static byte[] writeTime(Date date) {
return writeTime(date, null);
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null ) {
return false;
}
if ( getClass() != o.getClass() ) {
return false;
}
PwDate date = (PwDate) o;
if ( cDateBuilt && date.cDateBuilt ) {
return Arrays.equals(cDate, date.cDate);
} else if ( jDateBuilt && date.jDateBuilt ) {
return IsSameDate(jDate, date.jDate);
} else if ( cDateBuilt && date.jDateBuilt ) {
return Arrays.equals(date.getCDate(), cDate);
} else {
return IsSameDate(date.getDate(), jDate);
}
}
public static byte[] writeTime(Date date, Calendar cal) {
if (date == null) {
return null;
}
private static boolean IsSameDate(Date d1, Date d2) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(d1);
cal1.set(Calendar.MILLISECOND, 0);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(d2);
cal2.set(Calendar.MILLISECOND, 0);
return (cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)) &&
(cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH)) &&
(cal1.get(Calendar.DAY_OF_MONTH) == cal2.get(Calendar.DAY_OF_MONTH)) &&
(cal1.get(Calendar.HOUR) == cal2.get(Calendar.HOUR)) &&
(cal1.get(Calendar.MINUTE) == cal2.get(Calendar.MINUTE)) &&
(cal1.get(Calendar.SECOND) == cal2.get(Calendar.SECOND));
}
byte[] buf = new byte[5];
if (cal == null) {
cal = Calendar.getInstance();
}
cal.setTime(date);
int year = cal.get(Calendar.YEAR);
// File format is a 1 based month, java Calendar uses a zero based month
int month = cal.get(Calendar.MONTH) + 1;
// File format is a 0 based day, java Calendar uses a 1 based day
int day = cal.get(Calendar.DAY_OF_MONTH) - 1;
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
buf[0] = Types.writeUByte(((year >> 6) & 0x0000003F));
buf[1] = Types.writeUByte(((year & 0x0000003F) << 2)
| ((month >> 2) & 0x00000003));
buf[2] = (byte) (((month & 0x00000003) << 6)
| ((day & 0x0000001F) << 1) | ((hour >> 4) & 0x00000001));
buf[3] = (byte) (((hour & 0x0000000F) << 4) | ((minute >> 2) & 0x0000000F));
buf[4] = (byte) (((minute & 0x00000003) << 6) | (second & 0x0000003F));
return buf;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null ) {
return false;
}
if ( getClass() != o.getClass() ) {
return false;
}
PwDate date = (PwDate) o;
if ( cDateBuilt && date.cDateBuilt ) {
return Arrays.equals(cDate, date.cDate);
} else if ( jDateBuilt && date.jDateBuilt ) {
return IsSameDate(jDate, date.jDate);
} else if ( cDateBuilt && date.jDateBuilt ) {
return Arrays.equals(date.getCDate(), cDate);
} else {
return IsSameDate(date.getDate(), jDate);
}
}
private static boolean IsSameDate(Date d1, Date d2) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(d1);
cal1.set(Calendar.MILLISECOND, 0);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(d2);
cal2.set(Calendar.MILLISECOND, 0);
return (cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)) &&
(cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH)) &&
(cal1.get(Calendar.DAY_OF_MONTH) == cal2.get(Calendar.DAY_OF_MONTH)) &&
(cal1.get(Calendar.HOUR) == cal2.get(Calendar.HOUR)) &&
(cal1.get(Calendar.MINUTE) == cal2.get(Calendar.MINUTE)) &&
(cal1.get(Calendar.SECOND) == cal2.get(Calendar.SECOND));
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -45,16 +45,16 @@ import com.kunzisoft.keepass.stylish.StylishActivity;
public class IconPickerDialogFragment extends DialogFragment {
public static final String KEY_ICON_STANDARD = "KEY_ICON_STANDARD";
public static final String KEY_ICON_STANDARD = "KEY_ICON_STANDARD";
private IconPickerListener iconPickerListener;
private IconPack iconPack;
private IconPickerListener iconPickerListener;
private IconPack iconPack;
public static void launch(StylishActivity activity) {
public static void launch(StylishActivity activity) {
// Create an instance of the dialog fragment and show it
IconPickerDialogFragment dialog = new IconPickerDialogFragment();
dialog.show(activity.getSupportFragmentManager(), "IconPickerDialogFragment");
}
}
@Override
public void onAttach(Context context) {
@@ -66,86 +66,86 @@ public class IconPickerDialogFragment extends DialogFragment {
throw new ClassCastException(context.toString()
+ " must implement " + IconPickerListener.class.getName());
}
}
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
iconPack = IconPackChooser.getSelectedIconPack(getContext());
iconPack = IconPackChooser.getSelectedIconPack(getContext());
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
View root = inflater.inflate(R.layout.icon_picker, null);
builder.setView(root);
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
View root = inflater.inflate(R.layout.icon_picker, null);
builder.setView(root);
GridView currIconGridView = root.findViewById(R.id.IconGridView);
currIconGridView.setAdapter(new ImageAdapter(this.getContext()));
GridView currIconGridView = root.findViewById(R.id.IconGridView);
currIconGridView.setAdapter(new ImageAdapter(this.getContext()));
currIconGridView.setOnItemClickListener((parent, v, position, id) -> {
currIconGridView.setOnItemClickListener((parent, v, position, id) -> {
Bundle bundle = new Bundle();
bundle.putParcelable(KEY_ICON_STANDARD, new PwIconStandard(position));
iconPickerListener.iconPicked(bundle);
bundle.putParcelable(KEY_ICON_STANDARD, new PwIconStandard(position));
iconPickerListener.iconPicked(bundle);
dismiss();
});
builder.setNegativeButton(R.string.cancel, (dialog, id) ->
IconPickerDialogFragment.this.getDialog().cancel());
IconPickerDialogFragment.this.getDialog().cancel());
return builder.create();
}
public class ImageAdapter extends BaseAdapter {
private Context context;
return builder.create();
}
ImageAdapter(Context c) {
context = c;
}
public class ImageAdapter extends BaseAdapter {
private Context context;
public int getCount() {
/* Return number of KeePass icons */
return iconPack.numberOfIcons();
}
public Object getItem(int position) {
return null;
}
ImageAdapter(Context c) {
context = c;
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
View currView;
if(convertView == null) {
LayoutInflater li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
public int getCount() {
/* Return number of KeePass icons */
return iconPack.numberOfIcons();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
View currView;
if(convertView == null) {
LayoutInflater li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
assert li != null;
currView = li.inflate(R.layout.icon, parent, false);
}
else {
currView = convertView;
}
ImageView iv = currView.findViewById(R.id.icon_image);
iv.setImageResource(iconPack.iconToResId(position));
}
else {
currView = convertView;
}
ImageView iv = currView.findViewById(R.id.icon_image);
iv.setImageResource(iconPack.iconToResId(position));
// Assign color if icons are tintable
if (iconPack.tintable()) {
// Retrieve the textColor to tint the icon
int[] attrs = {android.R.attr.textColor};
assert getContext() != null;
TypedArray ta = getContext().getTheme().obtainStyledAttributes(attrs);
int iconColor = ta.getColor(0, Color.BLACK);
// Assign color if icons are tintable
if (iconPack.tintable()) {
// Retrieve the textColor to tint the icon
int[] attrs = {android.R.attr.textColor};
assert getContext() != null;
TypedArray ta = getContext().getTheme().obtainStyledAttributes(attrs);
int iconColor = ta.getColor(0, Color.BLACK);
ImageViewCompat.setImageTintList(iv, ColorStateList.valueOf(iconColor));
}
}
return currView;
}
}
return currView;
}
}
public interface IconPickerListener {
void iconPicked(Bundle bundle);
}
public interface IconPickerListener {
void iconPicked(Bundle bundle);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -25,14 +25,14 @@ import android.os.Build;
import com.kunzisoft.keepass.R;
public class ReadOnlyDialog extends WarningDialog {
public ReadOnlyDialog(Context context) {
super(context, R.string.show_read_only_warning);
warning = context.getString(R.string.read_only_warning);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
warning = warning.concat("\n\n").concat(context.getString(R.string.read_only_kitkat_warning));
}
}
public ReadOnlyDialog(Context context) {
super(context, R.string.show_read_only_warning);
warning = context.getString(R.string.read_only_warning);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
warning = warning.concat("\n\n").concat(context.getString(R.string.read_only_kitkat_warning));
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -29,50 +29,50 @@ import android.preference.PreferenceManager;
import com.kunzisoft.keepass.R;
public class WarningDialog extends AlertDialog {
protected String warning;
private int showKey;
public WarningDialog(Context context, int dontShowKey) {
super(context);
this.showKey = dontShowKey;
}
public WarningDialog(Context context, int warningKey, int dontShowKey) {
this(context, dontShowKey);
protected String warning;
private int showKey;
warning = context.getString(warningKey);
}
public WarningDialog(Context context, int dontShowKey) {
super(context);
@Override
protected void onCreate(Bundle savedInstanceState) {
Context ctx = getContext();
setMessage(warning);
setButton(AlertDialog.BUTTON1, ctx.getText(android.R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
});
setButton(AlertDialog.BUTTON2, ctx.getText(R.string.beta_dontask), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Context ctx = getContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(ctx.getString(showKey), false);
edit.commit();
dismiss();
}
});
super.onCreate(savedInstanceState);
}
this.showKey = dontShowKey;
}
public WarningDialog(Context context, int warningKey, int dontShowKey) {
this(context, dontShowKey);
warning = context.getString(warningKey);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
Context ctx = getContext();
setMessage(warning);
setButton(AlertDialog.BUTTON1, ctx.getText(android.R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
});
setButton(AlertDialog.BUTTON2, ctx.getText(R.string.beta_dontask), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Context ctx = getContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(ctx.getString(showKey), false);
edit.commit();
dismiss();
}
});
super.onCreate(savedInstanceState);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -33,29 +33,29 @@ import com.kunzisoft.keepass.utils.Util;
public class BrowserDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
View root = inflater.inflate(R.layout.browser_install, null);
builder.setView(root)
.setNegativeButton(R.string.cancel, (dialog, id) -> { });
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
View root = inflater.inflate(R.layout.browser_install, null);
builder.setView(root)
.setNegativeButton(R.string.cancel, (dialog, id) -> { });
Button market = root.findViewById(R.id.install_market);
market.setOnClickListener((view) -> {
Util.gotoUrl(getContext(), R.string.filemanager_play_store);
dismiss();
});
Button market = root.findViewById(R.id.install_market);
market.setOnClickListener((view) -> {
Util.gotoUrl(getContext(), R.string.filemanager_play_store);
dismiss();
});
Button web = root.findViewById(R.id.install_web);
web.setOnClickListener(view -> {
Button web = root.findViewById(R.id.install_web);
web.setOnClickListener(view -> {
Util.gotoUrl(getContext(), R.string.filemanager_f_droid);
dismiss();
});
return builder.create();
}
return builder.create();
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -34,221 +34,221 @@ import java.io.FileFilter;
public class FileDbHelper {
private static final String TAG = FileDbHelper.class.getName();
public static final String LAST_FILENAME = "lastFile";
public static final String LAST_KEYFILE = "lastKey";
public static final String DATABASE_NAME = "keepassdroid"; // TODO Change db name
private static final String FILE_TABLE = "files";
private static final int DATABASE_VERSION = 1;
public static final int MAX_FILES = 5;
public static final String KEY_FILE_ID = "_id";
public static final String KEY_FILE_FILENAME = "fileName";
public static final String KEY_FILE_KEYFILE = "keyFile";
public static final String KEY_FILE_UPDATED = "updated";
private static final String DATABASE_CREATE =
"create table " + FILE_TABLE + " ( " + KEY_FILE_ID + " integer primary key autoincrement, "
+ KEY_FILE_FILENAME + " text not null, " + KEY_FILE_KEYFILE + " text, "
+ KEY_FILE_UPDATED + " integer not null);";
private final Context mCtx;
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private static class DatabaseHelper extends SQLiteOpenHelper {
private final Context mCtx;
DatabaseHelper(Context ctx) {
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
mCtx = ctx;
}
public static final String LAST_FILENAME = "lastFile";
public static final String LAST_KEYFILE = "lastKey";
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
// Migrate preference to database if it is set.
SharedPreferences settings = mCtx.getSharedPreferences("PasswordActivity", Context.MODE_PRIVATE);
String lastFile = settings.getString(LAST_FILENAME, "");
String lastKey = settings.getString(LAST_KEYFILE,"");
if ( lastFile.length() > 0 ) {
ContentValues vals = new ContentValues();
vals.put(KEY_FILE_FILENAME, lastFile);
vals.put(KEY_FILE_UPDATED, System.currentTimeMillis());
if ( lastKey.length() > 0 ) {
vals.put(KEY_FILE_KEYFILE, lastKey);
}
db.insert(FILE_TABLE, null, vals);
// Clear old preferences
deletePrefs(settings);
}
}
public static final String DATABASE_NAME = "keepassdroid"; // TODO Change db name
private static final String FILE_TABLE = "files";
private static final int DATABASE_VERSION = 1;
public static final int MAX_FILES = 5;
public static final String KEY_FILE_ID = "_id";
public static final String KEY_FILE_FILENAME = "fileName";
public static final String KEY_FILE_KEYFILE = "keyFile";
public static final String KEY_FILE_UPDATED = "updated";
private static final String DATABASE_CREATE =
"create table " + FILE_TABLE + " ( " + KEY_FILE_ID + " integer primary key autoincrement, "
+ KEY_FILE_FILENAME + " text not null, " + KEY_FILE_KEYFILE + " text, "
+ KEY_FILE_UPDATED + " integer not null);";
private final Context mCtx;
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private static class DatabaseHelper extends SQLiteOpenHelper {
private final Context mCtx;
DatabaseHelper(Context ctx) {
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
mCtx = ctx;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
// Migrate preference to database if it is set.
SharedPreferences settings = mCtx.getSharedPreferences("PasswordActivity", Context.MODE_PRIVATE);
String lastFile = settings.getString(LAST_FILENAME, "");
String lastKey = settings.getString(LAST_KEYFILE,"");
if ( lastFile.length() > 0 ) {
ContentValues vals = new ContentValues();
vals.put(KEY_FILE_FILENAME, lastFile);
vals.put(KEY_FILE_UPDATED, System.currentTimeMillis());
if ( lastKey.length() > 0 ) {
vals.put(KEY_FILE_KEYFILE, lastKey);
}
db.insert(FILE_TABLE, null, vals);
// Clear old preferences
deletePrefs(settings);
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Only one database version so far
}
private void deletePrefs(SharedPreferences prefs) {
// We won't worry too much if this fails
try {
SharedPreferences.Editor editor = prefs.edit();
editor.remove(LAST_FILENAME);
editor.remove(LAST_KEYFILE);
editor.apply();
} catch (Exception e) {
Log.e(TAG, "Unable to delete database preference", e);
}
}
}
public FileDbHelper(Context ctx) {
mCtx = ctx;
}
public FileDbHelper open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public boolean isOpen() {
return mDb.isOpen();
}
public void close() {
mDb.close();
}
public long createFile(String fileName, String keyFile) {
// Check to see if this filename is already used
Cursor cursor;
try {
cursor = mDb.query(true, FILE_TABLE, new String[] {KEY_FILE_ID},
KEY_FILE_FILENAME + "=?", new String[] {fileName}, null, null, null, null);
} catch (Exception e ) {
assert(true);
return -1;
}
long result;
// If there is an existing entry update it with the new key file
if ( cursor.getCount() > 0 ) {
cursor.moveToFirst();
long id = cursor.getLong(cursor.getColumnIndexOrThrow(KEY_FILE_ID));
ContentValues vals = new ContentValues();
vals.put(KEY_FILE_KEYFILE, keyFile);
vals.put(KEY_FILE_UPDATED, System.currentTimeMillis());
result = mDb.update(FILE_TABLE, vals, KEY_FILE_ID + " = " + id, null);
// Otherwise add the new entry
} else {
ContentValues vals = new ContentValues();
vals.put(KEY_FILE_FILENAME, fileName);
vals.put(KEY_FILE_KEYFILE, keyFile);
vals.put(KEY_FILE_UPDATED, System.currentTimeMillis());
result = mDb.insert(FILE_TABLE, null, vals);
}
// Delete all but the last five records
try {
deleteAllBut(MAX_FILES);
} catch (Exception e) {
e.printStackTrace();
assert(true);
}
cursor.close();
return result;
}
private void deleteAllBut(int limit) {
Cursor cursor = mDb.query(FILE_TABLE, new String[] {KEY_FILE_UPDATED}, null, null, null, null, KEY_FILE_UPDATED);
if ( cursor.getCount() > limit ) {
cursor.moveToFirst();
long time = cursor.getLong(cursor.getColumnIndexOrThrow(KEY_FILE_UPDATED));
mDb.execSQL("DELETE FROM " + FILE_TABLE + " WHERE " + KEY_FILE_UPDATED + "<" + time + ";");
}
cursor.close();
}
public void deleteAllKeys() {
ContentValues vals = new ContentValues();
vals.put(KEY_FILE_KEYFILE, "");
mDb.update(FILE_TABLE, vals, null, null);
}
public void deleteFile(String filename) {
mDb.delete(FILE_TABLE, KEY_FILE_FILENAME + " = ?", new String[] {filename});
}
public Cursor fetchAllFiles() {
Cursor ret;
ret = mDb.query(FILE_TABLE, new String[] {KEY_FILE_ID, KEY_FILE_FILENAME, KEY_FILE_KEYFILE }, null, null, null, null, KEY_FILE_UPDATED + " DESC", Integer.toString(MAX_FILES));
return ret;
}
public Cursor fetchFile(long fileId) throws SQLException {
Cursor cursor = mDb.query(true, FILE_TABLE, new String[] {KEY_FILE_FILENAME, KEY_FILE_KEYFILE},
KEY_FILE_ID + "=" + fileId, null, null, null, null, null);
if ( cursor != null ) {
cursor.moveToFirst();
}
return cursor;
}
public String getFileByName(String name) {
Cursor cursor = mDb.query(true, FILE_TABLE, new String[] {KEY_FILE_KEYFILE},
KEY_FILE_FILENAME + "= ?", new String[] {name}, null, null, null, null);
if ( cursor == null ) {
return "";
}
String filename;
if ( cursor.moveToFirst() ) {
filename = cursor.getString(0);
} else {
// Cursor is empty
filename = "";
}
cursor.close();
return filename;
}
public boolean hasRecentFiles() {
Cursor cursor = fetchAllFiles();
boolean hasRecent = cursor.getCount() > 0;
cursor.close();
return hasRecent;
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Only one database version so far
}
private void deletePrefs(SharedPreferences prefs) {
// We won't worry too much if this fails
try {
SharedPreferences.Editor editor = prefs.edit();
editor.remove(LAST_FILENAME);
editor.remove(LAST_KEYFILE);
editor.apply();
} catch (Exception e) {
Log.e(TAG, "Unable to delete database preference", e);
}
}
}
public FileDbHelper(Context ctx) {
mCtx = ctx;
}
public FileDbHelper open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public boolean isOpen() {
return mDb.isOpen();
}
public void close() {
mDb.close();
}
public long createFile(String fileName, String keyFile) {
// Check to see if this filename is already used
Cursor cursor;
try {
cursor = mDb.query(true, FILE_TABLE, new String[] {KEY_FILE_ID},
KEY_FILE_FILENAME + "=?", new String[] {fileName}, null, null, null, null);
} catch (Exception e ) {
assert(true);
return -1;
}
long result;
// If there is an existing entry update it with the new key file
if ( cursor.getCount() > 0 ) {
cursor.moveToFirst();
long id = cursor.getLong(cursor.getColumnIndexOrThrow(KEY_FILE_ID));
ContentValues vals = new ContentValues();
vals.put(KEY_FILE_KEYFILE, keyFile);
vals.put(KEY_FILE_UPDATED, System.currentTimeMillis());
result = mDb.update(FILE_TABLE, vals, KEY_FILE_ID + " = " + id, null);
// Otherwise add the new entry
} else {
ContentValues vals = new ContentValues();
vals.put(KEY_FILE_FILENAME, fileName);
vals.put(KEY_FILE_KEYFILE, keyFile);
vals.put(KEY_FILE_UPDATED, System.currentTimeMillis());
result = mDb.insert(FILE_TABLE, null, vals);
}
// Delete all but the last five records
try {
deleteAllBut(MAX_FILES);
} catch (Exception e) {
e.printStackTrace();
assert(true);
}
cursor.close();
return result;
}
private void deleteAllBut(int limit) {
Cursor cursor = mDb.query(FILE_TABLE, new String[] {KEY_FILE_UPDATED}, null, null, null, null, KEY_FILE_UPDATED);
if ( cursor.getCount() > limit ) {
cursor.moveToFirst();
long time = cursor.getLong(cursor.getColumnIndexOrThrow(KEY_FILE_UPDATED));
mDb.execSQL("DELETE FROM " + FILE_TABLE + " WHERE " + KEY_FILE_UPDATED + "<" + time + ";");
}
cursor.close();
}
public void deleteAllKeys() {
ContentValues vals = new ContentValues();
vals.put(KEY_FILE_KEYFILE, "");
mDb.update(FILE_TABLE, vals, null, null);
}
public void deleteFile(String filename) {
mDb.delete(FILE_TABLE, KEY_FILE_FILENAME + " = ?", new String[] {filename});
}
public Cursor fetchAllFiles() {
Cursor ret;
ret = mDb.query(FILE_TABLE, new String[] {KEY_FILE_ID, KEY_FILE_FILENAME, KEY_FILE_KEYFILE }, null, null, null, null, KEY_FILE_UPDATED + " DESC", Integer.toString(MAX_FILES));
return ret;
}
public Cursor fetchFile(long fileId) throws SQLException {
Cursor cursor = mDb.query(true, FILE_TABLE, new String[] {KEY_FILE_FILENAME, KEY_FILE_KEYFILE},
KEY_FILE_ID + "=" + fileId, null, null, null, null, null);
if ( cursor != null ) {
cursor.moveToFirst();
}
return cursor;
}
public String getFileByName(String name) {
Cursor cursor = mDb.query(true, FILE_TABLE, new String[] {KEY_FILE_KEYFILE},
KEY_FILE_FILENAME + "= ?", new String[] {name}, null, null, null, null);
if ( cursor == null ) {
return "";
}
String filename;
if ( cursor.moveToFirst() ) {
filename = cursor.getString(0);
} else {
// Cursor is empty
filename = "";
}
cursor.close();
return filename;
}
public boolean hasRecentFiles() {
Cursor cursor = fetchAllFiles();
boolean hasRecent = cursor.getCount() > 0;
cursor.close();
return hasRecent;
}
/**
* Deletes a database including its journal file and other auxiliary files
* that may have been created by the database engine.
@@ -257,7 +257,7 @@ public class FileDbHelper {
* @return True if the database was successfully deleted.
*/
public static boolean deleteDatabase(Context ctx) {
File file = ctx.getDatabasePath(DATABASE_NAME);
File file = ctx.getDatabasePath(DATABASE_NAME);
if (file == null) {
throw new IllegalArgumentException("file must not be null");
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -86,7 +86,7 @@ import permissions.dispatcher.RuntimePermissions;
public class FileSelectActivity extends StylishActivity implements
CreateFileDialogFragment.DefinePathDialogListener,
AssignMasterKeyDialogFragment.AssignPasswordDialogListener,
FileSelectAdapter.FileItemOpenListener,
FileSelectAdapter.FileItemOpenListener,
FileSelectAdapter.FileSelectClearListener,
FileSelectAdapter.FileInformationShowListener {
@@ -95,64 +95,64 @@ public class FileSelectActivity extends StylishActivity implements
private static final String EXTRA_STAY = "EXTRA_STAY";
private FileSelectAdapter mAdapter;
private View fileListContainer;
private View createButtonView;
private View browseButtonView;
private View openButtonView;
private View fileListContainer;
private View createButtonView;
private View browseButtonView;
private View openButtonView;
private RecentFileHistory fileHistory;
private RecentFileHistory fileHistory;
private View fileSelectExpandableButton;
private ExpandableLayout fileSelectExpandable;
private EditText openFileNameView;
private EditText openFileNameView;
private Uri databaseUri;
private Uri databaseUri;
private KeyFileHelper keyFileHelper;
private KeyFileHelper keyFileHelper;
private String defaultPath;
/*
* -------------------------
* No Standard Launch, pass by PasswordActivity
* -------------------------
*/
/*
* -------------------------
* No Standard Launch, pass by PasswordActivity
* -------------------------
*/
/*
* -------------------------
* Keyboard Launch
* -------------------------
*/
/*
* -------------------------
* Keyboard Launch
* -------------------------
*/
public static void launchForKeyboardSelection(Activity activity) {
KeyboardHelper.INSTANCE.startActivityForKeyboardSelection(activity, new Intent(activity, FileSelectActivity.class));
KeyboardHelper.INSTANCE.startActivityForKeyboardSelection(activity, new Intent(activity, FileSelectActivity.class));
}
/*
* -------------------------
* Autofill Launch
* -------------------------
*/
/*
* -------------------------
* Autofill Launch
* -------------------------
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public static void launchForAutofillResult(Activity activity, @NonNull AssistStructure assistStructure) {
AutofillHelper.INSTANCE.startActivityForAutofillResult(activity,
new Intent(activity, FileSelectActivity.class),
assistStructure);
}
@RequiresApi(api = Build.VERSION_CODES.O)
public static void launchForAutofillResult(Activity activity, @NonNull AssistStructure assistStructure) {
AutofillHelper.INSTANCE.startActivityForAutofillResult(activity,
new Intent(activity, FileSelectActivity.class),
assistStructure);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fileHistory = App.getFileHistory();
fileHistory = App.getFileHistory();
setContentView(R.layout.file_selection);
fileListContainer = findViewById(R.id.container_file_list);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle("");
setSupportActionBar(toolbar);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle("");
setSupportActionBar(toolbar);
openFileNameView = findViewById(R.id.file_filename);
@@ -175,37 +175,37 @@ public class FileSelectActivity extends StylishActivity implements
// History list
RecyclerView mListFiles = findViewById(R.id.file_list);
mListFiles.setLayoutManager(new LinearLayoutManager(this));
mListFiles.setLayoutManager(new LinearLayoutManager(this));
// Open button
openButtonView = findViewById(R.id.open_database);
// Open button
openButtonView = findViewById(R.id.open_database);
openButtonView.setOnClickListener(v -> {
String fileName = openFileNameView.getText().toString();
String fileName = openFileNameView.getText().toString();
if (fileName.isEmpty())
fileName = defaultPath;
launchPasswordActivityWithPath(fileName);
});
// Create button
createButtonView = findViewById(R.id.create_database);
// Create button
createButtonView = findViewById(R.id.create_database);
createButtonView .setOnClickListener(v ->
FileSelectActivityPermissionsDispatcher
.openCreateFileDialogFragmentWithPermissionCheck(FileSelectActivity.this)
);
);
keyFileHelper = new KeyFileHelper(this);
browseButtonView = findViewById(R.id.browse_button);
browseButtonView = findViewById(R.id.browse_button);
browseButtonView.setOnClickListener(keyFileHelper.getOpenFileOnClickViewListener(
() -> Uri.parse("file://" + openFileNameView.getText().toString())));
// Construct adapter with listeners
mAdapter = new FileSelectAdapter(FileSelectActivity.this, fileHistory.getDbList());
mAdapter.setOnItemClickListener(this);
mAdapter.setFileSelectClearListener(this);
mAdapter.setFileInformationShowListener(this);
mListFiles.setAdapter(mAdapter);
// Construct adapter with listeners
mAdapter = new FileSelectAdapter(FileSelectActivity.this, fileHistory.getDbList());
mAdapter.setOnItemClickListener(this);
mAdapter.setFileSelectClearListener(this);
mAdapter.setFileInformationShowListener(this);
mListFiles.setAdapter(mAdapter);
// Load default database if not an orientation change
// Load default database if not an orientation change
if (! (savedInstanceState != null
&& savedInstanceState.containsKey(EXTRA_STAY)
&& savedInstanceState.getBoolean(EXTRA_STAY, false)) ) {
@@ -234,55 +234,55 @@ public class FileSelectActivity extends StylishActivity implements
// For the first time show education
checkAndPerformedEducation();
}
}
private void fileNoFoundAction(FileNotFoundException e) {
String error = getString(R.string.file_not_found_content);
Toast.makeText(FileSelectActivity.this,
error, Toast.LENGTH_LONG).show();
Log.e(TAG, error, e);
}
private void fileNoFoundAction(FileNotFoundException e) {
String error = getString(R.string.file_not_found_content);
Toast.makeText(FileSelectActivity.this,
error, Toast.LENGTH_LONG).show();
Log.e(TAG, error, e);
}
private void launchPasswordActivity(String fileName, String keyFile) {
EntrySelectionHelper.INSTANCE.doEntrySelectionAction(getIntent(),
() -> {
try {
PasswordActivity.launch(FileSelectActivity.this,
fileName, keyFile);
} catch (FileNotFoundException e) {
fileNoFoundAction(e);
}
return null;
},
() -> {
try {
PasswordActivity.launchForKeyboardResult(FileSelectActivity.this,
fileName, keyFile);
finish();
} catch (FileNotFoundException e) {
fileNoFoundAction(e);
}
return null;
},
assistStructure -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
PasswordActivity.launchForAutofillResult(FileSelectActivity.this,
fileName, keyFile,
assistStructure);
} catch (FileNotFoundException e) {
fileNoFoundAction(e);
}
}
return null;
});
}
private void launchPasswordActivity(String fileName, String keyFile) {
EntrySelectionHelper.INSTANCE.doEntrySelectionAction(getIntent(),
() -> {
try {
PasswordActivity.launch(FileSelectActivity.this,
fileName, keyFile);
} catch (FileNotFoundException e) {
fileNoFoundAction(e);
}
return null;
},
() -> {
try {
PasswordActivity.launchForKeyboardResult(FileSelectActivity.this,
fileName, keyFile);
finish();
} catch (FileNotFoundException e) {
fileNoFoundAction(e);
}
return null;
},
assistStructure -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
PasswordActivity.launchForAutofillResult(FileSelectActivity.this,
fileName, keyFile,
assistStructure);
} catch (FileNotFoundException e) {
fileNoFoundAction(e);
}
}
return null;
});
}
private void launchPasswordActivityWithPath(String path) {
launchPasswordActivity(path, "");
// Delete flickering for kitkat <=
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
overridePendingTransition(0, 0);
private void launchPasswordActivityWithPath(String path) {
launchPasswordActivity(path, "");
// Delete flickering for kitkat <=
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
overridePendingTransition(0, 0);
}
private void updateExternalStorageWarning() {
@@ -440,10 +440,10 @@ public class FileSelectActivity extends StylishActivity implements
createFileDialogFragment.show(getSupportFragmentManager(), "createFileDialogFragment");
}
private void updateFileListVisibility() {
if(mAdapter.getItemCount() == 0)
private void updateFileListVisibility() {
if(mAdapter.getItemCount() == 0)
fileListContainer.setVisibility(View.INVISIBLE);
else
else
fileListContainer.setVisibility(View.VISIBLE);
}
@@ -451,64 +451,64 @@ public class FileSelectActivity extends StylishActivity implements
* Create file for database
* @return If not created, return false
*/
private boolean createDatabaseFile(Uri path) {
private boolean createDatabaseFile(Uri path) {
String pathString = URLDecoder.decode(path.getPath());
// Make sure file name exists
if (pathString.length() == 0) {
Log.e(TAG, getString(R.string.error_filename_required));
Toast.makeText(FileSelectActivity.this,
R.string.error_filename_required,
Toast.LENGTH_LONG).show();
return false;
}
String pathString = URLDecoder.decode(path.getPath());
// Make sure file name exists
if (pathString.length() == 0) {
Log.e(TAG, getString(R.string.error_filename_required));
Toast.makeText(FileSelectActivity.this,
R.string.error_filename_required,
Toast.LENGTH_LONG).show();
return false;
}
// Try to create the file
File file = new File(pathString);
try {
if (file.exists()) {
// Try to create the file
File file = new File(pathString);
try {
if (file.exists()) {
Log.e(TAG, getString(R.string.error_database_exists) + " " + file);
Toast.makeText(FileSelectActivity.this,
R.string.error_database_exists,
Toast.LENGTH_LONG).show();
return false;
}
File parent = file.getParentFile();
Toast.makeText(FileSelectActivity.this,
R.string.error_database_exists,
Toast.LENGTH_LONG).show();
return false;
}
File parent = file.getParentFile();
if ( parent == null || (parent.exists() && ! parent.isDirectory()) ) {
if ( parent == null || (parent.exists() && ! parent.isDirectory()) ) {
Log.e(TAG, getString(R.string.error_invalid_path) + " " + file);
Toast.makeText(FileSelectActivity.this,
R.string.error_invalid_path,
Toast.LENGTH_LONG).show();
return false;
}
Toast.makeText(FileSelectActivity.this,
R.string.error_invalid_path,
Toast.LENGTH_LONG).show();
return false;
}
if ( ! parent.exists() ) {
// Create parent directory
if ( ! parent.mkdirs() ) {
if ( ! parent.exists() ) {
// Create parent directory
if ( ! parent.mkdirs() ) {
Log.e(TAG, getString(R.string.error_could_not_create_parent) + " " + parent);
Toast.makeText(FileSelectActivity.this,
R.string.error_could_not_create_parent,
Toast.LENGTH_LONG).show();
return false;
}
}
Toast.makeText(FileSelectActivity.this,
R.string.error_could_not_create_parent,
Toast.LENGTH_LONG).show();
return false;
}
}
return file.createNewFile();
} catch (IOException e) {
return file.createNewFile();
} catch (IOException e) {
Log.e(TAG, getString(R.string.error_could_not_create_parent) + " " + e.getLocalizedMessage());
e.printStackTrace();
Toast.makeText(
FileSelectActivity.this,
getText(R.string.error_file_not_create) + " "
+ e.getLocalizedMessage(),
Toast.LENGTH_LONG).show();
return false;
}
}
Toast.makeText(
FileSelectActivity.this,
getText(R.string.error_file_not_create) + " "
+ e.getLocalizedMessage(),
Toast.LENGTH_LONG).show();
return false;
}
}
@Override
public boolean onDefinePathDialogPositiveClick(Uri pathFile) {
@Override
public boolean onDefinePathDialogPositiveClick(Uri pathFile) {
databaseUri = pathFile;
if(createDatabaseFile(pathFile)) {
AssignMasterKeyDialogFragment assignMasterKeyDialogFragment = new AssignMasterKeyDialogFragment();
@@ -516,97 +516,97 @@ public class FileSelectActivity extends StylishActivity implements
return true;
} else
return false;
}
}
@Override
public boolean onDefinePathDialogNegativeClick(Uri pathFile) {
@Override
public boolean onDefinePathDialogNegativeClick(Uri pathFile) {
return true;
}
}
@Override
public void onAssignKeyDialogPositiveClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
@Override
public void onAssignKeyDialogPositiveClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
try {
String databaseFilename = databaseUri.getPath();
try {
String databaseFilename = databaseUri.getPath();
if (databaseFilename != null) {
// Create the new database and start prof
new Thread(new ProgressDialogRunnable(this,
R.string.progress_create,
progressTaskUpdater ->
new CreateDatabaseRunnable(databaseFilename, database -> {
// TODO store database created
return new AssignPasswordInDatabaseRunnable(FileSelectActivity.this,
database,
masterPasswordChecked,
masterPassword,
keyFileChecked,
keyFile,
new LaunchGroupActivityFinish(UriUtil.parseDefaultFile(databaseFilename)),
true // TODO get readonly
);
})
)).start();
}
} catch (Exception e) {
String error = "Unable to create database with this password and key file";
Toast.makeText(this, error, Toast.LENGTH_LONG).show();
Log.e(TAG, error + " " + e.getMessage());
// TODO remove
e.printStackTrace();
}
}
if (databaseFilename != null) {
// Create the new database and start prof
new Thread(new ProgressDialogRunnable(this,
R.string.progress_create,
progressTaskUpdater ->
new CreateDatabaseRunnable(databaseFilename, database -> {
// TODO store database created
return new AssignPasswordInDatabaseRunnable(FileSelectActivity.this,
database,
masterPasswordChecked,
masterPassword,
keyFileChecked,
keyFile,
new LaunchGroupActivityFinish(UriUtil.parseDefaultFile(databaseFilename)),
true // TODO get readonly
);
})
)).start();
}
} catch (Exception e) {
String error = "Unable to create database with this password and key file";
Toast.makeText(this, error, Toast.LENGTH_LONG).show();
Log.e(TAG, error + " " + e.getMessage());
// TODO remove
e.printStackTrace();
}
}
private class LaunchGroupActivityFinish extends ActionRunnable {
private class LaunchGroupActivityFinish extends ActionRunnable {
private Uri fileURI;
private Uri fileURI;
LaunchGroupActivityFinish(Uri fileUri) {
super();
this.fileURI = fileUri;
}
LaunchGroupActivityFinish(Uri fileUri) {
super();
this.fileURI = fileUri;
}
@Override
public void run() {
finishRun(true, null);
}
@Override
public void run() {
finishRun(true, null);
}
@Override
public void onFinishRun(boolean isSuccess, @Nullable String message) {
runOnUiThread(() -> {
if (isSuccess) {
// Add database to recent files
fileHistory.createFile(fileURI);
mAdapter.notifyDataSetChanged();
updateFileListVisibility();
GroupActivity.launch(FileSelectActivity.this);
} else {
Log.e(TAG, "Unable to open the database");
}
});
}
}
@Override
public void onFinishRun(boolean isSuccess, @Nullable String message) {
runOnUiThread(() -> {
if (isSuccess) {
// Add database to recent files
fileHistory.createFile(fileURI);
mAdapter.notifyDataSetChanged();
updateFileListVisibility();
GroupActivity.launch(FileSelectActivity.this);
} else {
Log.e(TAG, "Unable to open the database");
}
});
}
}
@Override
public void onAssignKeyDialogNegativeClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
@Override
public void onAssignKeyDialogNegativeClick(
boolean masterPasswordChecked, String masterPassword,
boolean keyFileChecked, Uri keyFile) {
}
}
@Override
public void onFileItemOpenListener(int itemPosition) {
new OpenFileHistoryAsyncTask((fileName, keyFile) -> {
launchPasswordActivity(fileName, keyFile);
@Override
public void onFileItemOpenListener(int itemPosition) {
new OpenFileHistoryAsyncTask((fileName, keyFile) -> {
launchPasswordActivity(fileName, keyFile);
updateFileListVisibility();
}, fileHistory).execute(itemPosition);
}
}
@Override
public void onClickFileInformation(FileSelectBean fileSelectBean) {
if (fileSelectBean != null) {
if (fileSelectBean != null) {
FileInformationDialogFragment fileInformationDialogFragment =
FileInformationDialogFragment.newInstance(fileSelectBean);
fileInformationDialogFragment.show(getSupportFragmentManager(), "fileInformation");
@@ -623,15 +623,15 @@ public class FileSelectActivity extends StylishActivity implements
return true;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AutofillHelper.INSTANCE.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AutofillHelper.INSTANCE.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
}
keyFileHelper.onActivityResultCallback(requestCode, resultCode, data,
keyFileHelper.onActivityResultCallback(requestCode, resultCode, data,
uri -> {
if (uri != null) {
if (PreferencesUtil.autoOpenSelectedFile(FileSelectActivity.this)) {
@@ -642,7 +642,7 @@ public class FileSelectActivity extends StylishActivity implements
}
}
});
}
}
@OnShowRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
void showRationaleForExternalStorage(final PermissionRequest request) {
@@ -663,16 +663,16 @@ public class FileSelectActivity extends StylishActivity implements
Toast.makeText(this, R.string.permission_external_storage_never_ask, Toast.LENGTH_SHORT).show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuUtil.INSTANCE.defaultMenuInflater(getMenuInflater(), menu);
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuUtil.INSTANCE.defaultMenuInflater(getMenuInflater(), menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return MenuUtil.INSTANCE.onDefaultMenuOptionsItemSelected(this, item)
&& super.onOptionsItemSelected(item);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return MenuUtil.INSTANCE.onDefaultMenuOptionsItemSelected(this, item)
&& super.onOptionsItemSelected(item);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -48,21 +48,21 @@ public class IconDrawableFactory {
private static final String TAG = IconDrawableFactory.class.getName();
private static Drawable blank = null;
private static int blankWidth = -1;
private static int blankHeight = -1;
/** customIconMap
* Cache for icon drawable.
* Keys: UUID, Values: Drawables
*/
private ReferenceMap customIconMap = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
/** standardIconMap
* Cache for icon drawable.
* Keys: Integer, Values: Drawables
*/
private ReferenceMap standardIconMap = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
private static Drawable blank = null;
private static int blankWidth = -1;
private static int blankHeight = -1;
/** customIconMap
* Cache for icon drawable.
* Keys: UUID, Values: Drawables
*/
private ReferenceMap customIconMap = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
/** standardIconMap
* Cache for icon drawable.
* Keys: Integer, Values: Drawables
*/
private ReferenceMap standardIconMap = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
/**
* Assign a default database icon to an ImageView and tint it if needed
@@ -95,19 +95,19 @@ public class IconDrawableFactory {
* @param icon The icon from the database
* @param tintColor Use this color to tint tintable icon
*/
public void assignDatabaseIconTo(Context context, ImageView iconView, PwIcon icon, int tintColor) {
if (IconPackChooser.getSelectedIconPack(context).tintable()) {
public void assignDatabaseIconTo(Context context, ImageView iconView, PwIcon icon, int tintColor) {
if (IconPackChooser.getSelectedIconPack(context).tintable()) {
assignDrawableToImageView(getIconDrawable(context, icon, true, tintColor),
iconView,
true,
tintColor);
} else {
} else {
assignDrawableToImageView(getIconDrawable(context, icon, true, tintColor),
iconView,
false,
Color.WHITE);
}
}
}
}
/**
* Assign an image by its resourceId to an ImageView and tint it
@@ -146,9 +146,9 @@ public class IconDrawableFactory {
* @param icon The icon from database
* @return The build drawable
*/
public Drawable getIconDrawable(Context context, PwIcon icon) {
return getIconDrawable(context, icon, false, Color.WHITE).drawable;
}
public Drawable getIconDrawable(Context context, PwIcon icon) {
return getIconDrawable(context, icon, false, Color.WHITE).drawable;
}
/**
* Get the drawable icon from cache or build it and add it to the cache if not exists yet then tint it if needed
@@ -171,27 +171,27 @@ public class IconDrawableFactory {
* Build a blank drawable
* @param res Resource to build the drawable
*/
private static void initBlank(Resources res) {
if (blank==null) {
blankWidth = (int) res.getDimension(R.dimen.icon_size);
blankHeight = (int) res.getDimension(R.dimen.icon_size);
blank = new ColorDrawable(Color.TRANSPARENT);
blank.setBounds(0, 0, blankWidth, blankHeight);
}
}
private static void initBlank(Resources res) {
if (blank==null) {
blankWidth = (int) res.getDimension(R.dimen.icon_size);
blankHeight = (int) res.getDimension(R.dimen.icon_size);
blank = new ColorDrawable(Color.TRANSPARENT);
blank.setBounds(0, 0, blankWidth, blankHeight);
}
}
/**
* Key class to retrieve a Drawable in the cache if it's tinted or not
*/
private class CacheKey {
int resId;
boolean isTint;
int color;
private class CacheKey {
int resId;
boolean isTint;
int color;
CacheKey(int resId, boolean isTint, int color) {
this.resId = resId;
this.isTint = isTint;
this.color = color;
CacheKey(int resId, boolean isTint, int color) {
this.resId = resId;
this.isTint = isTint;
this.color = color;
}
@Override
@@ -202,7 +202,7 @@ public class IconDrawableFactory {
if (isTint)
return resId == cacheKey.resId &&
cacheKey.isTint &&
color == cacheKey.color;
color == cacheKey.color;
else
return resId == cacheKey.resId &&
!cacheKey.isTint;
@@ -218,11 +218,11 @@ public class IconDrawableFactory {
* @param tintColor Use this color if tint is true
* @return The drawable
*/
private Drawable getIconDrawable(Context context, PwIconStandard icon, boolean isTint, int tintColor) {
int resId = IconPackChooser.getSelectedIconPack(context).iconToResId(icon.getIconId());
private Drawable getIconDrawable(Context context, PwIconStandard icon, boolean isTint, int tintColor) {
int resId = IconPackChooser.getSelectedIconPack(context).iconToResId(icon.getIconId());
return getIconDrawable(context, resId, isTint, tintColor);
}
return getIconDrawable(context, resId, isTint, tintColor);
}
/**
* Get the drawable icon from cache or build it and add it to the cache if not exists yet
@@ -257,23 +257,23 @@ public class IconDrawableFactory {
return draw;
}
/**
* Utility class to prevent a custom icon to be tint
*/
private class SuperDrawable {
Drawable drawable;
boolean custom;
/**
* Utility class to prevent a custom icon to be tint
*/
private class SuperDrawable {
Drawable drawable;
boolean custom;
SuperDrawable(Drawable drawable) {
this.drawable = drawable;
this.custom = false;
SuperDrawable(Drawable drawable) {
this.drawable = drawable;
this.custom = false;
}
SuperDrawable(Drawable drawable, boolean custom) {
this.drawable = drawable;
this.custom = custom;
}
}
}
/**
* Build a custom icon from database
@@ -281,55 +281,55 @@ public class IconDrawableFactory {
* @param icon Icon from database
* @return The drawable
*/
private Drawable getIconDrawable(Context context, PwIconCustom icon) {
initBlank(context.getResources());
if (icon == null) {
return blank;
}
Drawable draw = (Drawable) customIconMap.get(icon.getUuid());
if (draw == null) {
private Drawable getIconDrawable(Context context, PwIconCustom icon) {
initBlank(context.getResources());
if (icon == null) {
return blank;
}
Bitmap bitmap = BitmapFactory.decodeByteArray(icon.getImageData(), 0, icon.getImageData().length);
// Could not understand custom icon
if (bitmap == null) {
return blank;
}
bitmap = resize(bitmap);
draw = new BitmapDrawable(context.getResources(), bitmap);
customIconMap.put(icon.getUuid(), draw);
}
Drawable draw = (Drawable) customIconMap.get(icon.getUuid());
return draw;
}
/**
if (draw == null) {
Bitmap bitmap = BitmapFactory.decodeByteArray(icon.getImageData(), 0, icon.getImageData().length);
// Could not understand custom icon
if (bitmap == null) {
return blank;
}
bitmap = resize(bitmap);
draw = new BitmapDrawable(context.getResources(), bitmap);
customIconMap.put(icon.getUuid(), draw);
}
return draw;
}
/**
* Resize the custom icon to match the built in icons
*
* @param bitmap Bitmap to resize
* @return Bitmap resized
*/
private Bitmap resize(Bitmap bitmap) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
if (width == blankWidth && height == blankHeight) {
return bitmap;
}
return Bitmap.createScaledBitmap(bitmap, blankWidth, blankHeight, true);
}
* @param bitmap Bitmap to resize
* @return Bitmap resized
*/
private Bitmap resize(Bitmap bitmap) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
if (width == blankWidth && height == blankHeight) {
return bitmap;
}
return Bitmap.createScaledBitmap(bitmap, blankWidth, blankHeight, true);
}
/**
* Clear the cache of icons
*/
public void clearCache() {
standardIconMap.clear();
customIconMap.clear();
}
public void clearCache() {
standardIconMap.clear();
customIconMap.clear();
}
}

View File

@@ -12,28 +12,28 @@ import static com.kunzisoft.keepass.magikeyboard.MagikIME.KEY_CHANGE_KEYBOARD;
public class MagikeyboardView extends KeyboardView {
public MagikeyboardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MagikeyboardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MagikeyboardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MagikeyboardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MagikeyboardView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MagikeyboardView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected boolean onLongPress(Keyboard.Key key) {
// TODO Action on long press
if (key.codes[0] == KEY_BACK_KEYBOARD) {
getOnKeyboardActionListener().onKey(KEY_CHANGE_KEYBOARD, null);
return true;
} else {
//Log.d("LatinKeyboardView", "KEY: " + key.codes[0]);
return super.onLongPress(key);
}
}
@Override
protected boolean onLongPress(Keyboard.Key key) {
// TODO Action on long press
if (key.codes[0] == KEY_BACK_KEYBOARD) {
getOnKeyboardActionListener().onKey(KEY_CHANGE_KEYBOARD, null);
return true;
} else {
//Log.d("LatinKeyboardView", "KEY: " + key.codes[0]);
return super.onLongPress(key);
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -26,14 +26,14 @@ import com.kunzisoft.keepass.R;
import java.security.SecureRandom;
public class PasswordGenerator {
private static final String UPPERCASE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String LOWERCASE_CHARS = "abcdefghijklmnopqrstuvwxyz";
private static final String DIGIT_CHARS = "0123456789";
private static final String MINUS_CHAR = "-";
private static final String UNDERLINE_CHAR = "_";
private static final String SPACE_CHAR = " ";
private static final String SPECIAL_CHARS = "!\"#$%&'*+,./:;=?@\\^`";
private static final String BRACKET_CHARS = "[]{}()<>";
private static final String UPPERCASE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String LOWERCASE_CHARS = "abcdefghijklmnopqrstuvwxyz";
private static final String DIGIT_CHARS = "0123456789";
private static final String MINUS_CHAR = "-";
private static final String UNDERLINE_CHAR = "_";
private static final String SPACE_CHAR = " ";
private static final String SPECIAL_CHARS = "!\"#$%&'*+,./:;=?@\\^`";
private static final String BRACKET_CHARS = "[]{}()<>";
// From KeePassXC code https://github.com/keepassxreboot/keepassxc/pull/538
private String extendedChars() {
@@ -48,14 +48,14 @@ public class PasswordGenerator {
charSet.append('\u00FF');
return charSet.toString();
}
private Context cxt;
public PasswordGenerator(Context cxt) {
this.cxt = cxt;
}
public String generatePassword(int length,
private Context cxt;
public PasswordGenerator(Context cxt) {
this.cxt = cxt;
}
public String generatePassword(int length,
boolean upperCase,
boolean lowerCase,
boolean digits,
@@ -65,13 +65,13 @@ public class PasswordGenerator {
boolean specials,
boolean brackets,
boolean extended) throws IllegalArgumentException{
// Desired password length is 0 or less
if (length <= 0) {
throw new IllegalArgumentException(cxt.getString(R.string.error_wrong_length));
}
// No option has been checked
if ( !upperCase
// Desired password length is 0 or less
if (length <= 0) {
throw new IllegalArgumentException(cxt.getString(R.string.error_wrong_length));
}
// No option has been checked
if ( !upperCase
&& !lowerCase
&& !digits
&& !minus
@@ -80,11 +80,11 @@ public class PasswordGenerator {
&& !specials
&& !brackets
&& !extended) {
throw new IllegalArgumentException(cxt.getString(R.string.error_pass_gen_type));
}
String characterSet = getCharacterSet(
upperCase,
throw new IllegalArgumentException(cxt.getString(R.string.error_pass_gen_type));
}
String characterSet = getCharacterSet(
upperCase,
lowerCase,
digits,
minus,
@@ -93,68 +93,68 @@ public class PasswordGenerator {
specials,
brackets,
extended);
int size = characterSet.length();
StringBuilder buffer = new StringBuilder();
SecureRandom random = new SecureRandom(); // use more secure variant of Random!
if (size > 0) {
for (int i = 0; i < length; i++) {
char c = characterSet.charAt((char) random.nextInt(size));
buffer.append(c);
}
}
return buffer.toString();
}
private String getCharacterSet(boolean upperCase,
boolean lowerCase,
boolean digits,
boolean minus,
boolean underline,
boolean space,
boolean specials,
boolean brackets,
boolean extended) {
StringBuilder charSet = new StringBuilder();
if (upperCase) {
charSet.append(UPPERCASE_CHARS);
}
if (lowerCase) {
charSet.append(LOWERCASE_CHARS);
}
if (digits) {
charSet.append(DIGIT_CHARS);
}
if (minus) {
charSet.append(MINUS_CHAR);
}
if (underline) {
charSet.append(UNDERLINE_CHAR);
}
if (space) {
charSet.append(SPACE_CHAR);
}
if (specials) {
charSet.append(SPECIAL_CHARS);
}
if (brackets) {
charSet.append(BRACKET_CHARS);
}
int size = characterSet.length();
if (extended) {
StringBuilder buffer = new StringBuilder();
SecureRandom random = new SecureRandom(); // use more secure variant of Random!
if (size > 0) {
for (int i = 0; i < length; i++) {
char c = characterSet.charAt((char) random.nextInt(size));
buffer.append(c);
}
}
return buffer.toString();
}
private String getCharacterSet(boolean upperCase,
boolean lowerCase,
boolean digits,
boolean minus,
boolean underline,
boolean space,
boolean specials,
boolean brackets,
boolean extended) {
StringBuilder charSet = new StringBuilder();
if (upperCase) {
charSet.append(UPPERCASE_CHARS);
}
if (lowerCase) {
charSet.append(LOWERCASE_CHARS);
}
if (digits) {
charSet.append(DIGIT_CHARS);
}
if (minus) {
charSet.append(MINUS_CHAR);
}
if (underline) {
charSet.append(UNDERLINE_CHAR);
}
if (space) {
charSet.append(SPACE_CHAR);
}
if (specials) {
charSet.append(SPECIAL_CHARS);
}
if (brackets) {
charSet.append(BRACKET_CHARS);
}
if (extended) {
charSet.append(extendedChars());
}
return charSet.toString();
}
return charSet.toString();
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -28,76 +28,76 @@ import java.io.OutputStream;
* output stream.
*/
public class CopyInputStream extends InputStream {
private InputStream is;
private OutputStream os;
public CopyInputStream(InputStream is, OutputStream os) {
this.is = is;
this.os = os;
}
private InputStream is;
private OutputStream os;
@Override
public int available() throws IOException {
return is.available();
}
public CopyInputStream(InputStream is, OutputStream os) {
this.is = is;
this.os = os;
}
@Override
public void close() throws IOException {
is.close();
os.close();
}
@Override
public int available() throws IOException {
return is.available();
}
@Override
public void mark(int readlimit) {
is.mark(readlimit);
}
@Override
public void close() throws IOException {
is.close();
os.close();
}
@Override
public boolean markSupported() {
return is.markSupported();
}
@Override
public void mark(int readlimit) {
is.mark(readlimit);
}
@Override
public int read() throws IOException {
int data = is.read();
if (data != -1) {
os.write(data);
}
return data;
}
@Override
public boolean markSupported() {
return is.markSupported();
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
int len = is.read(b, offset, length);
if (len != -1) {
os.write(b, offset, len);
}
return len;
}
@Override
public int read() throws IOException {
int data = is.read();
@Override
public int read(byte[] b) throws IOException {
int len = is.read(b);
if (len != -1) {
os.write(b, 0, len);
}
return len;
}
if (data != -1) {
os.write(data);
}
@Override
public synchronized void reset() throws IOException {
is.reset();
}
return data;
}
@Override
public long skip(long byteCount) throws IOException {
return is.skip(byteCount);
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
int len = is.read(b, offset, length);
if (len != -1) {
os.write(b, offset, len);
}
return len;
}
@Override
public int read(byte[] b) throws IOException {
int len = is.read(b);
if (len != -1) {
os.write(b, 0, len);
}
return len;
}
@Override
public synchronized void reset() throws IOException {
is.reset();
}
@Override
public long skip(long byteCount) throws IOException {
return is.skip(byteCount);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -23,60 +23,60 @@ import java.io.IOException;
import java.io.InputStream;
public class CountInputStream extends InputStream {
InputStream is;
long bytes = 0;
public CountInputStream(InputStream is) {
this.is = is;
}
InputStream is;
long bytes = 0;
@Override
public int available() throws IOException {
return is.available();
}
public CountInputStream(InputStream is) {
this.is = is;
}
@Override
public void close() throws IOException {
is.close();
}
@Override
public int available() throws IOException {
return is.available();
}
@Override
public void mark(int readlimit) {
is.mark(readlimit);
}
@Override
public void close() throws IOException {
is.close();
}
@Override
public boolean markSupported() {
return is.markSupported();
}
@Override
public void mark(int readlimit) {
is.mark(readlimit);
}
@Override
public int read() throws IOException {
bytes++;
return is.read();
}
@Override
public boolean markSupported() {
return is.markSupported();
}
@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
bytes += length;
return is.read(buffer, offset, length);
}
@Override
public int read() throws IOException {
bytes++;
return is.read();
}
@Override
public int read(byte[] buffer) throws IOException {
bytes += buffer.length;
return is.read(buffer);
}
@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
bytes += length;
return is.read(buffer, offset, length);
}
@Override
public synchronized void reset() throws IOException {
is.reset();
}
@Override
public int read(byte[] buffer) throws IOException {
bytes += buffer.length;
return is.read(buffer);
}
@Override
public long skip(long byteCount) throws IOException {
bytes += byteCount;
return is.skip(byteCount);
}
@Override
public synchronized void reset() throws IOException {
is.reset();
}
@Override
public long skip(long byteCount) throws IOException {
bytes += byteCount;
return is.skip(byteCount);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -23,40 +23,40 @@ import java.io.IOException;
import java.io.OutputStream;
public class CountOutputStream extends OutputStream {
OutputStream os;
long bytes = 0;
public CountOutputStream(OutputStream os) {
this.os = os;
}
OutputStream os;
long bytes = 0;
public CountOutputStream(OutputStream os) {
this.os = os;
}
@Override
public void close() throws IOException {
os.close();
}
@Override
public void close() throws IOException {
os.close();
}
@Override
public void flush() throws IOException {
os.flush();
}
@Override
public void flush() throws IOException {
os.flush();
}
@Override
public void write(byte[] buffer, int offset, int count) throws IOException {
bytes += count;
os.write(buffer, offset, count);
}
@Override
public void write(byte[] buffer, int offset, int count) throws IOException {
bytes += count;
os.write(buffer, offset, count);
}
@Override
public void write(byte[] buffer) throws IOException {
bytes += buffer.length;
os.write(buffer);
}
@Override
public void write(byte[] buffer) throws IOException {
bytes += buffer.length;
os.write(buffer);
}
@Override
public void write(int oneByte) throws IOException {
bytes++;
os.write(oneByte);
}
@Override
public void write(int oneByte) throws IOException {
bytes++;
os.write(oneByte);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -29,137 +29,137 @@ import java.util.Arrays;
public class HashedBlockInputStream extends InputStream {
private final static int HASH_SIZE = 32;
private LEDataInputStream baseStream;
private int bufferPos = 0;
private byte[] buffer = new byte[0];
private long bufferIndex = 0;
private boolean atEnd = false;
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
private final static int HASH_SIZE = 32;
public HashedBlockInputStream(InputStream is) {
baseStream = new LEDataInputStream(is);
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
if ( atEnd ) return -1;
int remaining = length;
while ( remaining > 0 ) {
if ( bufferPos == buffer.length ) {
// Get more from the source into the buffer
if ( ! ReadHashedBlock() ) {
return length - remaining;
}
}
private LEDataInputStream baseStream;
private int bufferPos = 0;
private byte[] buffer = new byte[0];
private long bufferIndex = 0;
private boolean atEnd = false;
// Copy from buffer out
int copyLen = Math.min(buffer.length - bufferPos, remaining);
System.arraycopy(buffer, bufferPos, b, offset, copyLen);
offset += copyLen;
bufferPos += copyLen;
remaining -= copyLen;
}
return length;
}
/**
* @return false, when the end of the source stream is reached
* @throws IOException
*/
private boolean ReadHashedBlock() throws IOException {
if ( atEnd ) return false;
bufferPos = 0;
long index = baseStream.readUInt();
if ( index != bufferIndex ) {
throw new IOException("Invalid data format");
}
bufferIndex++;
byte[] storedHash = baseStream.readBytes(32);
if ( storedHash == null || storedHash.length != HASH_SIZE) {
throw new IOException("Invalid data format");
}
int bufferSize = LEDataInputStream.readInt(baseStream);
if ( bufferSize < 0 ) {
throw new IOException("Invalid data format");
}
if ( bufferSize == 0 ) {
for (int hash = 0; hash < HASH_SIZE; hash++) {
if ( storedHash[hash] != 0 ) {
throw new IOException("Invalid data format");
}
}
atEnd = true;
buffer = new byte[0];
return false;
}
buffer = baseStream.readBytes(bufferSize);
if ( buffer == null || buffer.length != bufferSize ) {
throw new IOException("Invalid data format");
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new IOException("SHA-256 not implemented here.");
}
byte[] computedHash = md.digest(buffer);
if ( computedHash == null || computedHash.length != HASH_SIZE ) {
throw new IOException("Hash wrong size");
}
if ( ! Arrays.equals(storedHash, computedHash) ) {
throw new IOException("Hashes didn't match.");
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
return true;
}
public HashedBlockInputStream(InputStream is) {
baseStream = new LEDataInputStream(is);
}
@Override
public long skip(long n) throws IOException {
return 0;
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
if ( atEnd ) return -1;
@Override
public int read() throws IOException {
if ( atEnd ) return -1;
if ( bufferPos == buffer.length ) {
if ( ! ReadHashedBlock() ) return -1;
}
int output = Types.readUByte(buffer, bufferPos);
bufferPos++;
return output;
}
int remaining = length;
@Override
public void close() throws IOException {
baseStream.close();
}
while ( remaining > 0 ) {
if ( bufferPos == buffer.length ) {
// Get more from the source into the buffer
if ( ! ReadHashedBlock() ) {
return length - remaining;
}
}
// Copy from buffer out
int copyLen = Math.min(buffer.length - bufferPos, remaining);
System.arraycopy(buffer, bufferPos, b, offset, copyLen);
offset += copyLen;
bufferPos += copyLen;
remaining -= copyLen;
}
return length;
}
/**
* @return false, when the end of the source stream is reached
* @throws IOException
*/
private boolean ReadHashedBlock() throws IOException {
if ( atEnd ) return false;
bufferPos = 0;
long index = baseStream.readUInt();
if ( index != bufferIndex ) {
throw new IOException("Invalid data format");
}
bufferIndex++;
byte[] storedHash = baseStream.readBytes(32);
if ( storedHash == null || storedHash.length != HASH_SIZE) {
throw new IOException("Invalid data format");
}
int bufferSize = LEDataInputStream.readInt(baseStream);
if ( bufferSize < 0 ) {
throw new IOException("Invalid data format");
}
if ( bufferSize == 0 ) {
for (int hash = 0; hash < HASH_SIZE; hash++) {
if ( storedHash[hash] != 0 ) {
throw new IOException("Invalid data format");
}
}
atEnd = true;
buffer = new byte[0];
return false;
}
buffer = baseStream.readBytes(bufferSize);
if ( buffer == null || buffer.length != bufferSize ) {
throw new IOException("Invalid data format");
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new IOException("SHA-256 not implemented here.");
}
byte[] computedHash = md.digest(buffer);
if ( computedHash == null || computedHash.length != HASH_SIZE ) {
throw new IOException("Hash wrong size");
}
if ( ! Arrays.equals(storedHash, computedHash) ) {
throw new IOException("Hashes didn't match.");
}
return true;
}
@Override
public long skip(long n) throws IOException {
return 0;
}
@Override
public int read() throws IOException {
if ( atEnd ) return -1;
if ( bufferPos == buffer.length ) {
if ( ! ReadHashedBlock() ) return -1;
}
int output = Types.readUByte(buffer, bufferPos);
bufferPos++;
return output;
}
@Override
public void close() throws IOException {
baseStream.close();
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -26,90 +26,90 @@ import java.security.NoSuchAlgorithmException;
public class HashedBlockOutputStream extends OutputStream {
private final static int DEFAULT_BUFFER_SIZE = 1024 * 1024;
private LEDataOutputStream baseStream;
private int bufferPos = 0;
private byte[] buffer;
private long bufferIndex = 0;
public HashedBlockOutputStream(OutputStream os) {
init(os, DEFAULT_BUFFER_SIZE);
}
public HashedBlockOutputStream(OutputStream os, int bufferSize) {
if ( bufferSize <= 0 ) {
bufferSize = DEFAULT_BUFFER_SIZE;
}
init(os, bufferSize);
}
private void init(OutputStream os, int bufferSize) {
baseStream = new LEDataOutputStream(os);
buffer = new byte[bufferSize];
}
private final static int DEFAULT_BUFFER_SIZE = 1024 * 1024;
@Override
public void write(int oneByte) throws IOException {
byte[] buf = new byte[1];
buf[0] = (byte)oneByte;
write(buf, 0, 1);
}
private LEDataOutputStream baseStream;
private int bufferPos = 0;
private byte[] buffer;
private long bufferIndex = 0;
@Override
public void close() throws IOException {
if ( bufferPos != 0 ) {
// Write remaining buffered amount
WriteHashedBlock();
}
// Write terminating block
WriteHashedBlock();
flush();
baseStream.close();
}
public HashedBlockOutputStream(OutputStream os) {
init(os, DEFAULT_BUFFER_SIZE);
}
@Override
public void flush() throws IOException {
baseStream.flush();
}
public HashedBlockOutputStream(OutputStream os, int bufferSize) {
if ( bufferSize <= 0 ) {
bufferSize = DEFAULT_BUFFER_SIZE;
}
@Override
public void write(byte[] b, int offset, int count) throws IOException {
while ( count > 0 ) {
if ( bufferPos == buffer.length ) {
WriteHashedBlock();
}
int copyLen = Math.min(buffer.length - bufferPos, count);
System.arraycopy(b, offset, buffer, bufferPos, copyLen);
offset += copyLen;
bufferPos += copyLen;
count -= copyLen;
}
}
init(os, bufferSize);
}
private void WriteHashedBlock() throws IOException {
baseStream.writeUInt(bufferIndex);
bufferIndex++;
if ( bufferPos > 0 ) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new IOException("SHA-256 not implemented here.");
}
byte[] hash;
md.update(buffer, 0, bufferPos);
hash = md.digest();
private void init(OutputStream os, int bufferSize) {
baseStream = new LEDataOutputStream(os);
buffer = new byte[bufferSize];
}
@Override
public void write(int oneByte) throws IOException {
byte[] buf = new byte[1];
buf[0] = (byte)oneByte;
write(buf, 0, 1);
}
@Override
public void close() throws IOException {
if ( bufferPos != 0 ) {
// Write remaining buffered amount
WriteHashedBlock();
}
// Write terminating block
WriteHashedBlock();
flush();
baseStream.close();
}
@Override
public void flush() throws IOException {
baseStream.flush();
}
@Override
public void write(byte[] b, int offset, int count) throws IOException {
while ( count > 0 ) {
if ( bufferPos == buffer.length ) {
WriteHashedBlock();
}
int copyLen = Math.min(buffer.length - bufferPos, count);
System.arraycopy(b, offset, buffer, bufferPos, copyLen);
offset += copyLen;
bufferPos += copyLen;
count -= copyLen;
}
}
private void WriteHashedBlock() throws IOException {
baseStream.writeUInt(bufferIndex);
bufferIndex++;
if ( bufferPos > 0 ) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new IOException("SHA-256 not implemented here.");
}
byte[] hash;
md.update(buffer, 0, bufferPos);
hash = md.digest();
/*
if ( bufferPos == buffer.length) {
hash = md.digest(buffer);
@@ -119,30 +119,30 @@ public class HashedBlockOutputStream extends OutputStream {
hash = md.digest(b);
}
*/
baseStream.write(hash);
} else {
// Write 32-bits of zeros
baseStream.writeLong(0L);
baseStream.writeLong(0L);
baseStream.writeLong(0L);
baseStream.writeLong(0L);
}
baseStream.writeInt(bufferPos);
if ( bufferPos > 0 ) {
baseStream.write(buffer, 0, bufferPos);
}
bufferPos = 0;
}
baseStream.write(hash);
@Override
public void write(byte[] buffer) throws IOException {
write(buffer, 0, buffer.length);
}
} else {
// Write 32-bits of zeros
baseStream.writeLong(0L);
baseStream.writeLong(0L);
baseStream.writeLong(0L);
baseStream.writeLong(0L);
}
baseStream.writeInt(bufferPos);
if ( bufferPos > 0 ) {
baseStream.write(buffer, 0, bufferPos);
}
bufferPos = 0;
}
@Override
public void write(byte[] buffer) throws IOException {
write(buffer, 0, buffer.length);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -30,100 +30,100 @@ import java.util.Arrays;
*/
public class LEDataInputStream extends InputStream {
private static final long INT_TO_LONG_MASK = 0xffffffffL;
private InputStream baseStream;
private static final long INT_TO_LONG_MASK = 0xffffffffL;
public LEDataInputStream(InputStream in) {
baseStream = in;
}
/** Read a 32-bit value and return it as a long, so that it can
* be interpreted as an unsigned integer.
* @return
* @throws IOException
*/
public long readUInt() throws IOException {
return readUInt(baseStream);
}
public int readInt() throws IOException {
return readInt(baseStream);
}
public long readLong() throws IOException {
byte[] buf = readBytes(8);
return readLong(buf, 0);
}
@Override
public int available() throws IOException {
return baseStream.available();
}
private InputStream baseStream;
@Override
public void close() throws IOException {
baseStream.close();
}
public LEDataInputStream(InputStream in) {
baseStream = in;
}
@Override
public void mark(int readlimit) {
baseStream.mark(readlimit);
}
/** Read a 32-bit value and return it as a long, so that it can
* be interpreted as an unsigned integer.
* @return
* @throws IOException
*/
public long readUInt() throws IOException {
return readUInt(baseStream);
}
@Override
public boolean markSupported() {
return baseStream.markSupported();
}
public int readInt() throws IOException {
return readInt(baseStream);
}
@Override
public int read() throws IOException {
return baseStream.read();
}
public long readLong() throws IOException {
byte[] buf = readBytes(8);
@Override
public int read(byte[] b, int offset, int length) throws IOException {
return baseStream.read(b, offset, length);
}
return readLong(buf, 0);
}
@Override
public int read(byte[] b) throws IOException {
// TODO Auto-generated method stub
return super.read(b);
}
@Override
public int available() throws IOException {
return baseStream.available();
}
@Override
public synchronized void reset() throws IOException {
baseStream.reset();
}
@Override
public void close() throws IOException {
baseStream.close();
}
@Override
public long skip(long n) throws IOException {
return baseStream.skip(n);
}
@Override
public void mark(int readlimit) {
baseStream.mark(readlimit);
}
public byte[] readBytes(int length) throws IOException {
// TODO Exception max length < buffer size
byte[] buf = new byte[length];
@Override
public boolean markSupported() {
return baseStream.markSupported();
}
int count = 0;
while ( count < length ) {
int read = read(buf, count, length - count);
// Reached end
if ( read == -1 ) {
// Stop early
byte[] early = new byte[count];
System.arraycopy(buf, 0, early, 0, count);
return early;
}
count += read;
}
return buf;
}
@Override
public int read() throws IOException {
return baseStream.read();
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
return baseStream.read(b, offset, length);
}
@Override
public int read(byte[] b) throws IOException {
// TODO Auto-generated method stub
return super.read(b);
}
@Override
public synchronized void reset() throws IOException {
baseStream.reset();
}
@Override
public long skip(long n) throws IOException {
return baseStream.skip(n);
}
public byte[] readBytes(int length) throws IOException {
// TODO Exception max length < buffer size
byte[] buf = new byte[length];
int count = 0;
while ( count < length ) {
int read = read(buf, count, length - count);
// Reached end
if ( read == -1 ) {
// Stop early
byte[] early = new byte[count];
System.arraycopy(buf, 0, early, 0, count);
return early;
}
count += read;
}
return buf;
}
public void readBytes(int length, ActionReadBytes actionReadBytes) throws IOException {
int bufferSize = 256 * 3; // TODO Buffer size
@@ -152,62 +152,62 @@ public class LEDataInputStream extends InputStream {
}
}
public static int readUShort(InputStream is) throws IOException {
byte[] buf = new byte[2];
is.read(buf, 0, 2);
return readUShort(buf, 0);
}
public int readUShort() throws IOException {
return readUShort(baseStream);
}
public static int readUShort(InputStream is) throws IOException {
byte[] buf = new byte[2];
/**
* Read an unsigned 16-bit value.
*
* @param buf
* @param offset
* @return
*/
public static int readUShort( byte[] buf, int offset ) {
return (buf[offset] & 0xFF) + ((buf[offset + 1] & 0xFF) << 8);
}
is.read(buf, 0, 2);
public static long readLong( byte buf[], int offset ) {
return ((long)buf[offset] & 0xFF) + (((long)buf[offset + 1] & 0xFF) << 8)
+ (((long)buf[offset + 2] & 0xFF) << 16) + (((long)buf[offset + 3] & 0xFF) << 24)
+ (((long)buf[offset + 4] & 0xFF) << 32) + (((long)buf[offset + 5] & 0xFF) << 40)
+ (((long)buf[offset + 6] & 0xFF) << 48) + (((long)buf[offset + 7] & 0xFF) << 56);
}
return readUShort(buf, 0);
}
public static long readUInt( byte buf[], int offset ) {
return (readInt(buf, offset) & INT_TO_LONG_MASK);
}
public int readUShort() throws IOException {
return readUShort(baseStream);
}
public static int readInt(InputStream is) throws IOException {
byte[] buf = new byte[4];
is.read(buf, 0, 4);
return readInt(buf, 0);
}
/**
* Read an unsigned 16-bit value.
*
* @param buf
* @param offset
* @return
*/
public static int readUShort( byte[] buf, int offset ) {
return (buf[offset] & 0xFF) + ((buf[offset + 1] & 0xFF) << 8);
}
public static long readUInt(InputStream is) throws IOException {
return (readInt(is) & INT_TO_LONG_MASK);
}
public static long readLong( byte buf[], int offset ) {
return ((long)buf[offset] & 0xFF) + (((long)buf[offset + 1] & 0xFF) << 8)
+ (((long)buf[offset + 2] & 0xFF) << 16) + (((long)buf[offset + 3] & 0xFF) << 24)
+ (((long)buf[offset + 4] & 0xFF) << 32) + (((long)buf[offset + 5] & 0xFF) << 40)
+ (((long)buf[offset + 6] & 0xFF) << 48) + (((long)buf[offset + 7] & 0xFF) << 56);
}
/**
* Read a 32-bit value.
*
* @param buf
* @param offset
* @return
*/
public static int readInt( byte buf[], int offset ) {
return (buf[offset] & 0xFF) + ((buf[offset + 1] & 0xFF) << 8) + ((buf[offset + 2] & 0xFF) << 16)
+ ((buf[offset + 3] & 0xFF) << 24);
}
public static long readUInt( byte buf[], int offset ) {
return (readInt(buf, offset) & INT_TO_LONG_MASK);
}
public static int readInt(InputStream is) throws IOException {
byte[] buf = new byte[4];
is.read(buf, 0, 4);
return readInt(buf, 0);
}
public static long readUInt(InputStream is) throws IOException {
return (readInt(is) & INT_TO_LONG_MASK);
}
/**
* Read a 32-bit value.
*
* @param buf
* @param offset
* @return
*/
public static int readInt( byte buf[], int offset ) {
return (buf[offset] & 0xFF) + ((buf[offset + 1] & 0xFF) << 8) + ((buf[offset + 2] & 0xFF) << 16)
+ ((buf[offset + 3] & 0xFF) << 24);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -29,116 +29,116 @@ import java.io.OutputStream;
*/
public class LEDataOutputStream extends OutputStream {
private OutputStream baseStream;
public LEDataOutputStream(OutputStream out) {
baseStream = out;
}
public void writeUInt(long uint) throws IOException {
baseStream.write(LEDataOutputStream.writeIntBuf((int) uint));
}
private OutputStream baseStream;
@Override
public void close() throws IOException {
baseStream.close();
}
public LEDataOutputStream(OutputStream out) {
baseStream = out;
}
@Override
public void flush() throws IOException {
baseStream.flush();
}
public void writeUInt(long uint) throws IOException {
baseStream.write(LEDataOutputStream.writeIntBuf((int) uint));
}
@Override
public void write(byte[] buffer, int offset, int count) throws IOException {
baseStream.write(buffer, offset, count);
}
@Override
public void close() throws IOException {
baseStream.close();
}
@Override
public void write(byte[] buffer) throws IOException {
baseStream.write(buffer);
}
@Override
public void flush() throws IOException {
baseStream.flush();
}
@Override
public void write(int oneByte) throws IOException {
baseStream.write(oneByte);
}
public void writeLong(long val) throws IOException {
byte[] buf = new byte[8];
writeLong(val, buf, 0);
baseStream.write(buf);
}
public void writeInt(int val) throws IOException {
byte[] buf = new byte[4];
writeInt(val, buf, 0);
baseStream.write(buf);
}
public void writeUShort(int val) throws IOException {
byte[] buf = new byte[2];
writeUShort(val, buf, 0);
baseStream.write(buf);
}
@Override
public void write(byte[] buffer, int offset, int count) throws IOException {
baseStream.write(buffer, offset, count);
}
public static byte[] writeIntBuf(int val) {
byte[] buf = new byte[4];
writeInt(val, buf, 0);
return buf;
}
@Override
public void write(byte[] buffer) throws IOException {
baseStream.write(buffer);
}
public static byte[] writeUShortBuf(int val) {
byte[] buf = new byte[2];
writeUShort(val, buf, 0);
return buf;
}
@Override
public void write(int oneByte) throws IOException {
baseStream.write(oneByte);
}
/** Write an unsigned 16-bit value
*
* @param val
* @param buf
* @param offset
*/
public static void writeUShort(int val, byte[] buf, int offset) {
buf[offset + 0] = (byte)(val & 0x00FF);
buf[offset + 1] = (byte)((val & 0xFF00) >> 8);
}
public void writeLong(long val) throws IOException {
byte[] buf = new byte[8];
/**
* Write a 32-bit value.
*
* @param val
* @param buf
* @param offset
*/
public static void writeInt( int val, byte[] buf, int offset ) {
buf[offset + 0] = (byte)(val & 0xFF);
buf[offset + 1] = (byte)((val >>> 8) & 0xFF);
buf[offset + 2] = (byte)((val >>> 16) & 0xFF);
buf[offset + 3] = (byte)((val >>> 24) & 0xFF);
}
public static byte[] writeLongBuf(long val) {
byte[] buf = new byte[8];
writeLong(val, buf, 0);
return buf;
}
writeLong(val, buf, 0);
baseStream.write(buf);
}
public static void writeLong( long val, byte[] buf, int offset ) {
buf[offset + 0] = (byte)(val & 0xFF);
buf[offset + 1] = (byte)((val >>> 8) & 0xFF);
buf[offset + 2] = (byte)((val >>> 16) & 0xFF);
buf[offset + 3] = (byte)((val >>> 24) & 0xFF);
buf[offset + 4] = (byte)((val >>> 32) & 0xFF);
buf[offset + 5] = (byte)((val >>> 40) & 0xFF);
buf[offset + 6] = (byte)((val >>> 48) & 0xFF);
buf[offset + 7] = (byte)((val >>> 56) & 0xFF);
}
public void writeInt(int val) throws IOException {
byte[] buf = new byte[4];
writeInt(val, buf, 0);
baseStream.write(buf);
}
public void writeUShort(int val) throws IOException {
byte[] buf = new byte[2];
writeUShort(val, buf, 0);
baseStream.write(buf);
}
public static byte[] writeIntBuf(int val) {
byte[] buf = new byte[4];
writeInt(val, buf, 0);
return buf;
}
public static byte[] writeUShortBuf(int val) {
byte[] buf = new byte[2];
writeUShort(val, buf, 0);
return buf;
}
/** Write an unsigned 16-bit value
*
* @param val
* @param buf
* @param offset
*/
public static void writeUShort(int val, byte[] buf, int offset) {
buf[offset + 0] = (byte)(val & 0x00FF);
buf[offset + 1] = (byte)((val & 0xFF00) >> 8);
}
/**
* Write a 32-bit value.
*
* @param val
* @param buf
* @param offset
*/
public static void writeInt( int val, byte[] buf, int offset ) {
buf[offset + 0] = (byte)(val & 0xFF);
buf[offset + 1] = (byte)((val >>> 8) & 0xFF);
buf[offset + 2] = (byte)((val >>> 16) & 0xFF);
buf[offset + 3] = (byte)((val >>> 24) & 0xFF);
}
public static byte[] writeLongBuf(long val) {
byte[] buf = new byte[8];
writeLong(val, buf, 0);
return buf;
}
public static void writeLong( long val, byte[] buf, int offset ) {
buf[offset + 0] = (byte)(val & 0xFF);
buf[offset + 1] = (byte)((val >>> 8) & 0xFF);
buf[offset + 2] = (byte)((val >>> 16) & 0xFF);
buf[offset + 3] = (byte)((val >>> 24) & 0xFF);
buf[offset + 4] = (byte)((val >>> 32) & 0xFF);
buf[offset + 5] = (byte)((val >>> 40) & 0xFF);
buf[offset + 6] = (byte)((val >>> 48) & 0xFF);
buf[offset + 7] = (byte)((val >>> 56) & 0xFF);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -24,28 +24,28 @@ import java.io.OutputStream;
public class NullOutputStream extends OutputStream {
@Override
public void close() throws IOException {
super.close();
}
@Override
public void close() throws IOException {
super.close();
}
@Override
public void flush() throws IOException {
super.flush();
}
@Override
public void flush() throws IOException {
super.flush();
}
@Override
public void write(byte[] buffer, int offset, int count) throws IOException {
super.write(buffer, offset, count);
}
@Override
public void write(byte[] buffer, int offset, int count) throws IOException {
super.write(buffer, offset, count);
}
@Override
public void write(byte[] buffer) throws IOException {
super.write(buffer);
}
@Override
public void write(byte[] buffer) throws IOException {
super.write(buffer);
}
@Override
public void write(int oneByte) throws IOException {
}
@Override
public void write(int oneByte) throws IOException {
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -25,40 +25,40 @@ 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();
}
RandomAccessFile mFile;
@Override
public void write(byte[] buffer, int offset, int count) throws IOException {
super.write(buffer, offset, count);
mFile.write(buffer, offset, count);
}
RandomFileOutputStream(RandomAccessFile file) {
mFile = file;
}
@Override
public void write(byte[] buffer) throws IOException {
super.write(buffer);
mFile.write(buffer);
}
@Override
public void close() throws IOException {
super.close();
@Override
public void write(int oneByte) throws IOException {
mFile.write(oneByte);
}
public void seek(long pos) throws IOException {
mFile.seek(pos);
}
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);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -24,19 +24,19 @@ import android.net.Uri;
import com.kunzisoft.keepass.database.element.PwDate;
public class EmptyUtils {
public static boolean isNullOrEmpty(String str) {
return (str == null) || (str.length() == 0);
}
public static boolean isNullOrEmpty(byte[] buf) {
return (buf == null) || (buf.length == 0);
}
public static boolean isNullOrEmpty(PwDate date) {
return (date == null) || date.equals(PwDate.DEFAULT_PWDATE);
}
public static boolean isNullOrEmpty(String str) {
return (str == null) || (str.length() == 0);
}
public static boolean isNullOrEmpty(Uri uri) {
return (uri==null) || (uri.toString().length() == 0);
}
public static boolean isNullOrEmpty(byte[] buf) {
return (buf == null) || (buf.length == 0);
}
public static boolean isNullOrEmpty(PwDate date) {
return (date == null) || date.equals(PwDate.DEFAULT_PWDATE);
}
public static boolean isNullOrEmpty(Uri uri) {
return (uri==null) || (uri.toString().length() == 0);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -27,24 +27,24 @@ import android.content.pm.ResolveInfo;
import java.util.List;
public class Interaction {
/**
* Indicates whether the specified action can be used as an intent. This
* method queries the package manager for installed packages that can
* respond to an intent with the specified action. If no suitable package is
* found, this method returns false.
*
* @param context The application's environment.
* @param action The Intent action to check for availability.
*
* @return True if an Intent with the specified action can be sent and
* responded to, false otherwise.
*/
public static boolean isIntentAvailable(Context context, String action) {
final PackageManager packageManager = context.getPackageManager();
final Intent intent = new Intent(action);
List<ResolveInfo> list =
packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
/**
* Indicates whether the specified action can be used as an intent. This
* method queries the package manager for installed packages that can
* respond to an intent with the specified action. If no suitable package is
* found, this method returns false.
*
* @param context The application's environment.
* @param action The Intent action to check for availability.
*
* @return True if an Intent with the specified action can be sent and
* responded to, false otherwise.
*/
public static boolean isIntentAvailable(Context context, String action) {
final PackageManager packageManager = context.getPackageManager();
final Intent intent = new Intent(action);
List<ResolveInfo> list =
packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -30,221 +30,221 @@ import java.util.*;
import java.util.Map.Entry;
public class SprEngineV4 {
private static final int MAX_RECURSION_DEPTH = 12;
private static final String STR_REF_START = "{REF:";
private static final String STR_REF_END = "}";
private static final int MAX_RECURSION_DEPTH = 12;
private static final String STR_REF_START = "{REF:";
private static final String STR_REF_END = "}";
public class TargetResult {
public PwEntryV4 entry;
public char wanted;
public class TargetResult {
public PwEntryV4 entry;
public char wanted;
public TargetResult(PwEntryV4 entry, char wanted) {
this.entry = entry;
this.wanted = wanted;
}
}
public TargetResult(PwEntryV4 entry, char wanted) {
this.entry = entry;
this.wanted = wanted;
}
}
private class SprContextV4 {
private class SprContextV4 {
public PwDatabaseV4 db;
public PwEntryV4 entry;
public Map<String, String> refsCache = new HashMap<>();
public PwDatabaseV4 db;
public PwEntryV4 entry;
public Map<String, String> refsCache = new HashMap<>();
SprContextV4(PwDatabaseV4 db, PwEntryV4 entry) {
this.db = db;
this.entry = entry;
}
SprContextV4(PwDatabaseV4 db, PwEntryV4 entry) {
this.db = db;
this.entry = entry;
}
SprContextV4(SprContextV4 source) {
this.db = source.db;
this.entry = source.entry;
this.refsCache = source.refsCache;
}
}
SprContextV4(SprContextV4 source) {
this.db = source.db;
this.entry = source.entry;
this.refsCache = source.refsCache;
}
}
public String compile(String text, PwEntryV4 entry, PwDatabase database) {
SprContextV4 ctx = new SprContextV4((PwDatabaseV4)database, entry);
public String compile(String text, PwEntryV4 entry, PwDatabase database) {
SprContextV4 ctx = new SprContextV4((PwDatabaseV4)database, entry);
return compileInternal(text, ctx, 0);
}
return compileInternal(text, ctx, 0);
}
private String compileInternal(String text, SprContextV4 sprContextV4, int recursionLevel) {
if (text == null) { return ""; }
if (sprContextV4 == null) { return ""; }
if (recursionLevel >= MAX_RECURSION_DEPTH) { return ""; }
private String compileInternal(String text, SprContextV4 sprContextV4, int recursionLevel) {
if (text == null) { return ""; }
if (sprContextV4 == null) { return ""; }
if (recursionLevel >= MAX_RECURSION_DEPTH) { return ""; }
return fillRefPlaceholders(text, sprContextV4, recursionLevel);
}
return fillRefPlaceholders(text, sprContextV4, recursionLevel);
}
private String fillRefPlaceholders(String text, SprContextV4 contextV4, int recursionLevel) {
private String fillRefPlaceholders(String text, SprContextV4 contextV4, int recursionLevel) {
if (contextV4.db == null) { return text; }
if (contextV4.db == null) { return text; }
int offset = 0;
for (int i = 0; i < 20; ++i) {
text = fillRefsUsingCache(text, contextV4);
int offset = 0;
for (int i = 0; i < 20; ++i) {
text = fillRefsUsingCache(text, contextV4);
int start = StringUtil.INSTANCE.indexOfIgnoreCase(text, STR_REF_START, offset, Locale.ENGLISH);
if (start < 0) { break; }
int end = StringUtil.INSTANCE.indexOfIgnoreCase(text, STR_REF_END, start + 1, Locale.ENGLISH);
if (end <= start) { break; }
int start = StringUtil.INSTANCE.indexOfIgnoreCase(text, STR_REF_START, offset, Locale.ENGLISH);
if (start < 0) { break; }
int end = StringUtil.INSTANCE.indexOfIgnoreCase(text, STR_REF_END, start + 1, Locale.ENGLISH);
if (end <= start) { break; }
String fullRef = text.substring(start, end - start + 1);
TargetResult result = findRefTarget(fullRef, contextV4);
String fullRef = text.substring(start, end - start + 1);
TargetResult result = findRefTarget(fullRef, contextV4);
if (result != null) {
if (result != null) {
PwEntryV4 found = result.entry;
char wanted = result.wanted;
if (found != null) {
String data;
switch (wanted) {
case 'T':
data = found.getTitle();
break;
case 'U':
data = found.getUsername();
break;
case 'A':
data = found.getUrl();
break;
case 'P':
data = found.getPassword();
break;
case 'N':
data = found.getNotes();
break;
case 'I':
data = found.getNodeId().toString();
break;
default:
offset = start + 1;
continue;
}
String data;
switch (wanted) {
case 'T':
data = found.getTitle();
break;
case 'U':
data = found.getUsername();
break;
case 'A':
data = found.getUrl();
break;
case 'P':
data = found.getPassword();
break;
case 'N':
data = found.getNotes();
break;
case 'I':
data = found.getNodeId().toString();
break;
default:
offset = start + 1;
continue;
}
SprContextV4 subCtx = new SprContextV4(contextV4);
subCtx.entry = found;
SprContextV4 subCtx = new SprContextV4(contextV4);
subCtx.entry = found;
String innerContent = compileInternal(data, subCtx, recursionLevel + 1);
addRefsToCache(fullRef, innerContent, contextV4);
text = fillRefsUsingCache(text, contextV4);
String innerContent = compileInternal(data, subCtx, recursionLevel + 1);
addRefsToCache(fullRef, innerContent, contextV4);
text = fillRefsUsingCache(text, contextV4);
} else {
offset = start + 1;
offset = start + 1;
}
}
}
}
return text;
}
private TargetResult findRefTarget(String fullRef, SprContextV4 contextV4) {
if (fullRef == null) { return null; }
fullRef = fullRef.toUpperCase(Locale.ENGLISH);
if (!fullRef.startsWith(STR_REF_START) || !fullRef.endsWith(STR_REF_END)) {
return null;
}
String ref = fullRef.substring(STR_REF_START.length(), fullRef.length() - STR_REF_START.length() - STR_REF_END.length());
if (ref.length() <= 4) { return null; }
if (ref.charAt(1) != '@') { return null; }
if (ref.charAt(3) != ':') { return null; }
char scan = Character.toUpperCase(ref.charAt(2));
char wanted = Character.toUpperCase(ref.charAt(0));
SearchParametersV4 searchParametersV4 = new SearchParametersV4();
searchParametersV4.setupNone();
searchParametersV4.setSearchString(ref.substring(4));
if (scan == 'T') { searchParametersV4.setSearchInTitles(true); }
else if (scan == 'U') { searchParametersV4.setSearchInUserNames(true); }
else if (scan == 'A') { searchParametersV4.setSearchInUrls(true); }
else if (scan == 'P') { searchParametersV4.setSearchInPasswords(true); }
else if (scan == 'N') { searchParametersV4.setSearchInNotes(true); }
else if (scan == 'I') { searchParametersV4.setSearchInUUIDs(true); }
else if (scan == 'O') { searchParametersV4.setSearchInOther(true); }
else { return null; }
List<PwEntryV4> list = new ArrayList<>();
// TODO type parameter
searchEntries(contextV4.db.getRootGroup(), searchParametersV4, list);
if (list.size() > 0) {
return new TargetResult(list.get(0), wanted);
}
return null;
}
return text;
}
private void addRefsToCache(String ref, String value, SprContextV4 ctx) {
if (ref == null) { return; }
if (value == null) { return; }
if (ctx == null) { return; }
private TargetResult findRefTarget(String fullRef, SprContextV4 contextV4) {
if (fullRef == null) { return null; }
if (!ctx.refsCache.containsKey(ref)) {
ctx.refsCache.put(ref, value);
}
}
fullRef = fullRef.toUpperCase(Locale.ENGLISH);
if (!fullRef.startsWith(STR_REF_START) || !fullRef.endsWith(STR_REF_END)) {
return null;
}
private String fillRefsUsingCache(String text, SprContextV4 sprContextV4) {
for (Entry<String, String> entry : sprContextV4.refsCache.entrySet()) {
text = StringUtil.INSTANCE.replaceAllIgnoresCase(text, entry.getKey(), entry.getValue(), Locale.ENGLISH);
}
String ref = fullRef.substring(STR_REF_START.length(), fullRef.length() - STR_REF_START.length() - STR_REF_END.length());
if (ref.length() <= 4) { return null; }
if (ref.charAt(1) != '@') { return null; }
if (ref.charAt(3) != ':') { return null; }
return text;
}
char scan = Character.toUpperCase(ref.charAt(2));
char wanted = Character.toUpperCase(ref.charAt(0));
private void searchEntries(PwGroupV4 root, SearchParametersV4 searchParametersV4, List<PwEntryV4> listStorage) {
if (searchParametersV4 == null) { return; }
if (listStorage == null) { return; }
SearchParametersV4 searchParametersV4 = new SearchParametersV4();
searchParametersV4.setupNone();
List<String> terms = StringUtil.INSTANCE.splitStringTerms(searchParametersV4.getSearchString());
if (terms.size() <= 1 || searchParametersV4.getRegularExpression()) {
root.doForEachChild(new EntrySearchHandlerV4(searchParametersV4, listStorage), null);
return;
}
searchParametersV4.setSearchString(ref.substring(4));
if (scan == 'T') { searchParametersV4.setSearchInTitles(true); }
else if (scan == 'U') { searchParametersV4.setSearchInUserNames(true); }
else if (scan == 'A') { searchParametersV4.setSearchInUrls(true); }
else if (scan == 'P') { searchParametersV4.setSearchInPasswords(true); }
else if (scan == 'N') { searchParametersV4.setSearchInNotes(true); }
else if (scan == 'I') { searchParametersV4.setSearchInUUIDs(true); }
else if (scan == 'O') { searchParametersV4.setSearchInOther(true); }
else { return null; }
// Search longest term first
Comparator<String> stringLengthComparator = (lhs, rhs) -> lhs.length() - rhs.length();
Collections.sort(terms, stringLengthComparator);
List<PwEntryV4> list = new ArrayList<>();
// TODO type parameter
searchEntries(contextV4.db.getRootGroup(), searchParametersV4, list);
String fullSearch = searchParametersV4.getSearchString();
List<PwEntryV4> childEntries = root.getChildEntries();
for (int i = 0; i < terms.size(); i ++) {
List<PwEntryV4> pgNew = new ArrayList<>();
if (list.size() > 0) {
return new TargetResult(list.get(0), wanted);
}
searchParametersV4.setSearchString(terms.get(i));
return null;
}
boolean negate = false;
if (searchParametersV4.getSearchString().startsWith("-")) {
searchParametersV4.setSearchString(searchParametersV4.getSearchString().substring(1));
negate = searchParametersV4.getSearchString().length() > 0;
}
private void addRefsToCache(String ref, String value, SprContextV4 ctx) {
if (ref == null) { return; }
if (value == null) { return; }
if (ctx == null) { return; }
if (!root.doForEachChild(new EntrySearchHandlerV4(searchParametersV4, pgNew), null)) {
childEntries = null;
break;
}
if (!ctx.refsCache.containsKey(ref)) {
ctx.refsCache.put(ref, value);
}
}
List<PwEntryV4> complement = new ArrayList<>();
if (negate) {
for (PwEntryV4 entry: childEntries) {
if (!pgNew.contains(entry)) {
complement.add(entry);
}
}
childEntries = complement;
}
else {
childEntries = pgNew;
}
}
private String fillRefsUsingCache(String text, SprContextV4 sprContextV4) {
for (Entry<String, String> entry : sprContextV4.refsCache.entrySet()) {
text = StringUtil.INSTANCE.replaceAllIgnoresCase(text, entry.getKey(), entry.getValue(), Locale.ENGLISH);
}
if (childEntries != null) {
listStorage.addAll(childEntries);
}
searchParametersV4.setSearchString(fullSearch);
}
return text;
}
private void searchEntries(PwGroupV4 root, SearchParametersV4 searchParametersV4, List<PwEntryV4> listStorage) {
if (searchParametersV4 == null) { return; }
if (listStorage == null) { return; }
List<String> terms = StringUtil.INSTANCE.splitStringTerms(searchParametersV4.getSearchString());
if (terms.size() <= 1 || searchParametersV4.getRegularExpression()) {
root.doForEachChild(new EntrySearchHandlerV4(searchParametersV4, listStorage), null);
return;
}
// Search longest term first
Comparator<String> stringLengthComparator = (lhs, rhs) -> lhs.length() - rhs.length();
Collections.sort(terms, stringLengthComparator);
String fullSearch = searchParametersV4.getSearchString();
List<PwEntryV4> childEntries = root.getChildEntries();
for (int i = 0; i < terms.size(); i ++) {
List<PwEntryV4> pgNew = new ArrayList<>();
searchParametersV4.setSearchString(terms.get(i));
boolean negate = false;
if (searchParametersV4.getSearchString().startsWith("-")) {
searchParametersV4.setSearchString(searchParametersV4.getSearchString().substring(1));
negate = searchParametersV4.getSearchString().length() > 0;
}
if (!root.doForEachChild(new EntrySearchHandlerV4(searchParametersV4, pgNew), null)) {
childEntries = null;
break;
}
List<PwEntryV4> complement = new ArrayList<>();
if (negate) {
for (PwEntryV4 entry: childEntries) {
if (!pgNew.contains(entry)) {
complement.add(entry);
}
}
childEntries = complement;
}
else {
childEntries = pgNew;
}
}
if (childEntries != null) {
listStorage.addAll(childEntries);
}
searchParametersV4.setSearchString(fullSearch);
}
}

View File

@@ -52,131 +52,131 @@ import java.util.UUID;
/**
* Tools for slicing and dicing Java and KeePass data types.
*
*
* @author Bill Zwicky <wrzwicky@pobox.com>
*/
public class Types {
public static long ULONG_MAX_VALUE = -1;
public static long ULONG_MAX_VALUE = -1;
/** Read an unsigned byte */
public static int readUByte( byte[] buf, int offset ) {
return ((int)buf[offset] & 0xFF);
}
/** Read an unsigned byte */
public static int readUByte( byte[] buf, int offset ) {
return ((int)buf[offset] & 0xFF);
}
/** Write an unsigned byte
*
* @param val
* @param buf
* @param offset
*/
public static void writeUByte(int val, byte[] buf, int offset) {
buf[offset] = (byte)(val & 0xFF);
}
public static byte writeUByte(int val) {
byte[] buf = new byte[1];
writeUByte(val, buf, 0);
return buf[0];
}
/** Write an unsigned byte
*
* @param val
* @param buf
* @param offset
*/
public static void writeUByte(int val, byte[] buf, int offset) {
buf[offset] = (byte)(val & 0xFF);
}
/**
* Return len of null-terminated string (i.e. distance to null)
* within a byte buffer.
*
* @param buf
* @param offset
* @return
*/
public static int strlen( byte[] buf, int offset ) {
int len = 0;
while( buf[offset + len] != 0 )
len++;
return len;
}
public static byte writeUByte(int val) {
byte[] buf = new byte[1];
writeUByte(val, buf, 0);
return buf[0];
}
/**
* Return len of null-terminated string (i.e. distance to null)
* within a byte buffer.
*
* @param buf
* @param offset
* @return
*/
public static int strlen( byte[] buf, int offset ) {
int len = 0;
while( buf[offset + len] != 0 )
len++;
return len;
}
/**
* Copy a sequence of bytes into a new array.
*
* @param b - source array
* @param offset - first byte
* @param len - number of bytes
* @return new byte[len]
*/
public static byte[] extract( byte[] b, int offset, int len ) {
byte[] b2 = new byte[len];
System.arraycopy( b, offset, b2, 0, len );
return b2;
}
private static final byte[] CRLFbuf = { 0x0D, 0x0A };
private static final String CRLF = new String(CRLFbuf);
private static final String SEP = System.getProperty("line.separator");
private static final boolean REPLACE = ! SEP.equals(CRLF);
public static String readCString(byte[] buf, int offset) throws UnsupportedEncodingException {
String jstring = new String(buf, offset, strlen(buf, offset), "UTF-8");
if ( REPLACE ) {
jstring = jstring.replace(CRLF, SEP);
}
return jstring;
}
/**
* Copy a sequence of bytes into a new array.
*
* @param b - source array
* @param offset - first byte
* @param len - number of bytes
* @return new byte[len]
*/
public static byte[] extract( byte[] b, int offset, int len ) {
byte[] b2 = new byte[len];
System.arraycopy( b, offset, b2, 0, len );
return b2;
}
public static int writeCString(String str, OutputStream os) throws IOException {
if ( str == null ) {
// Write out a null character
os.write(LEDataOutputStream.writeIntBuf(1));
os.write(0x00);
return 0;
}
if ( REPLACE ) {
str = str.replace(SEP, CRLF);
}
byte[] initial = str.getBytes("UTF-8");
int length = initial.length+1;
os.write(LEDataOutputStream.writeIntBuf(length));
os.write(initial);
os.write(0x00);
return length;
}
public static UUID bytestoUUID(byte[] buf) {
return bytestoUUID(buf, 0);
}
public static UUID bytestoUUID(byte[] buf, int offset) {
long lsb = 0;
for (int i = 15; i >= 8; i--) {
lsb = (lsb << 8) | (buf[i + offset] & 0xff);
}
long msb = 0;
for (int i = 7; i >= 0; i--) {
msb = (msb << 8) | (buf[i + offset] & 0xff);
}
return new UUID(msb, lsb);
private static final byte[] CRLFbuf = { 0x0D, 0x0A };
private static final String CRLF = new String(CRLFbuf);
private static final String SEP = System.getProperty("line.separator");
private static final boolean REPLACE = ! SEP.equals(CRLF);
public static String readCString(byte[] buf, int offset) throws UnsupportedEncodingException {
String jstring = new String(buf, offset, strlen(buf, offset), "UTF-8");
if ( REPLACE ) {
jstring = jstring.replace(CRLF, SEP);
}
return jstring;
}
public static int writeCString(String str, OutputStream os) throws IOException {
if ( str == null ) {
// Write out a null character
os.write(LEDataOutputStream.writeIntBuf(1));
os.write(0x00);
return 0;
}
if ( REPLACE ) {
str = str.replace(SEP, CRLF);
}
byte[] initial = str.getBytes("UTF-8");
int length = initial.length+1;
os.write(LEDataOutputStream.writeIntBuf(length));
os.write(initial);
os.write(0x00);
return length;
}
public static UUID bytestoUUID(byte[] buf) {
return bytestoUUID(buf, 0);
}
public static UUID bytestoUUID(byte[] buf, int offset) {
long lsb = 0;
for (int i = 15; i >= 8; i--) {
lsb = (lsb << 8) | (buf[i + offset] & 0xff);
}
long msb = 0;
for (int i = 7; i >= 0; i--) {
msb = (msb << 8) | (buf[i + offset] & 0xff);
}
return new UUID(msb, lsb);
}
public static byte[] UUIDtoBytes(UUID uuid) {
byte[] buf = new byte[16];
LEDataOutputStream.writeLong(uuid.getMostSignificantBits(), buf, 0);
LEDataOutputStream.writeLong(uuid.getLeastSignificantBits(), buf, 8);
return buf;
}
}
public static byte[] UUIDtoBytes(UUID uuid) {
byte[] buf = new byte[16];
LEDataOutputStream.writeLong(uuid.getMostSignificantBits(), buf, 0);
LEDataOutputStream.writeLong(uuid.getLeastSignificantBits(), buf, 8);
return buf;
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -34,18 +34,18 @@ import com.kunzisoft.keepass.R;
public class Util {
public static void gotoUrl(Context context, String url) throws ActivityNotFoundException {
if ( url != null && url.length() > 0 ) {
Uri uri = Uri.parse(url);
context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
}
}
public static void gotoUrl(Context context, int resId) throws ActivityNotFoundException {
gotoUrl(context, context.getString(resId));
}
public static void gotoUrl(Context context, String url) throws ActivityNotFoundException {
if ( url != null && url.length() > 0 ) {
Uri uri = Uri.parse(url);
context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
}
}
/**
public static void gotoUrl(Context context, int resId) throws ActivityNotFoundException {
gotoUrl(context, context.getString(resId));
}
/**
* Replace font by monospace, must be called after seText()
*/
public static void applyFontVisibilityTo(final Context context, final TextView textView) {
@@ -56,28 +56,28 @@ public class Util {
/**
* Replace font by monospace, must be called after seText()
*/
public static void applyFontVisibilityTo(final Context context, final EditText editText) {
public static void applyFontVisibilityTo(final Context context, final EditText editText) {
applyFontVisibilityTo(context, (TextView) editText);
}
}
public static float getListTextDefaultSize(Context context) {
return Float.parseFloat(context.getString(R.string.list_size_default));
}
public static float getListTextDefaultSize(Context context) {
return Float.parseFloat(context.getString(R.string.list_size_default));
}
public static void lockScreenOrientation(Activity activity) {
if (activity != null) {
int currentOrientation = activity.getResources().getConfiguration().orientation;
if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
if (activity != null) {
int currentOrientation = activity.getResources().getConfiguration().orientation;
if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
} else {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
}
}
}
}
public static void unlockScreenOrientation(Activity activity) {
if (activity != null) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
@@ -22,44 +22,44 @@ package com.kunzisoft.keepass.utils;
import java.util.UUID;
public class UuidUtil {
public static String toHexString(UUID uuid) {
if (uuid == null) { return null; }
byte[] buf = Types.UUIDtoBytes(uuid);
if (buf == null) { return null; }
int len = buf.length;
if (len == 0) { return ""; }
StringBuilder sb = new StringBuilder();
short bt;
char high, low;
for (int i = 0; i < len; i++) {
bt = (short)(buf[i] & 0xFF);
high = (char)(bt >>> 4);
low = (char)(bt & 0x0F);
char h,l;
h = byteToChar(high);
l = byteToChar(low);
public static String toHexString(UUID uuid) {
if (uuid == null) { return null; }
sb.append(byteToChar(high));
sb.append(byteToChar(low));
}
return sb.toString();
}
// Use short to represent unsigned byte
private static char byteToChar(char bt) {
byte[] buf = Types.UUIDtoBytes(uuid);
if (buf == null) { return null; }
int len = buf.length;
if (len == 0) { return ""; }
StringBuilder sb = new StringBuilder();
short bt;
char high, low;
for (int i = 0; i < len; i++) {
bt = (short)(buf[i] & 0xFF);
high = (char)(bt >>> 4);
low = (char)(bt & 0x0F);
char h,l;
h = byteToChar(high);
l = byteToChar(low);
sb.append(byteToChar(high));
sb.append(byteToChar(low));
}
return sb.toString();
}
// Use short to represent unsigned byte
private static char byteToChar(char bt) {
if (bt >= 10) {
return (char)('A' + bt - 10);
}
else {
return (char)('0' + bt);
}
}
}
}