mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Fix small crypto code
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||||
*
|
*
|
||||||
* This file is part of KeePass DX.
|
* This file is part of KeePass DX.
|
||||||
*
|
*
|
||||||
@@ -17,20 +17,18 @@
|
|||||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.crypto;
|
package com.kunzisoft.keepass.crypto
|
||||||
|
|
||||||
import java.security.Provider;
|
import java.security.Provider
|
||||||
|
|
||||||
public final class AESProvider extends Provider {
|
class AESProvider : Provider("AESProvider", 1.0, "") {
|
||||||
|
init {
|
||||||
|
put("Cipher.AES", NativeAESCipherSpi::class.java.name)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
companion object {
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = -3846349284296062658L;
|
|
||||||
|
|
||||||
public AESProvider() {
|
private const val serialVersionUID = -3846349284296062658L
|
||||||
super("AESProvider", 1.0, "");
|
|
||||||
put("Cipher.AES",NativeAESCipherSpi.class.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ public class CipherFactory {
|
|||||||
|
|
||||||
public static Cipher getInstance(String transformation, boolean androidOverride) throws NoSuchAlgorithmException, NoSuchPaddingException {
|
public static Cipher getInstance(String transformation, boolean androidOverride) throws NoSuchAlgorithmException, NoSuchPaddingException {
|
||||||
// Return the native AES if it is possible
|
// Return the native AES if it is possible
|
||||||
if ( (!deviceBlacklisted()) && (!androidOverride) && hasNativeImplementation(transformation) && NativeLib.loaded() ) {
|
if ( (!deviceBlacklisted()) && (!androidOverride) && hasNativeImplementation(transformation) && NativeLib.INSTANCE.loaded() ) {
|
||||||
return Cipher.getInstance(transformation, new AESProvider());
|
return Cipher.getInstance(transformation, new AESProvider());
|
||||||
} else {
|
} else {
|
||||||
return Cipher.getInstance(transformation);
|
return Cipher.getInstance(transformation);
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ public class NativeAESCipherSpi extends CipherSpi {
|
|||||||
private final int AES_BLOCK_SIZE = 16;
|
private final int AES_BLOCK_SIZE = 16;
|
||||||
private byte[] mIV;
|
private byte[] mIV;
|
||||||
|
|
||||||
private boolean mIsInited = false;
|
private boolean mIsInit = false;
|
||||||
private boolean mEncrypting = false;
|
|
||||||
private long mCtxPtr;
|
private long mCtxPtr;
|
||||||
|
|
||||||
private boolean mPadding = false;
|
private boolean mPadding = false;
|
||||||
@@ -68,7 +67,7 @@ public class NativeAESCipherSpi extends CipherSpi {
|
|||||||
|
|
||||||
private static void addToCleanupQueue(NativeAESCipherSpi ref, long ptr) {
|
private static void addToCleanupQueue(NativeAESCipherSpi ref, long ptr) {
|
||||||
Log.d(TAG, "queued cipher context: " + ptr);
|
Log.d(TAG, "queued cipher context: " + ptr);
|
||||||
mCleanup.put(new PhantomReference<NativeAESCipherSpi>(ref, mQueue), ptr);
|
mCleanup.put(new PhantomReference<>(ref, mQueue), ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Work with the garbage collector to clean up openssl memory when the cipher
|
/** Work with the garbage collector to clean up openssl memory when the cipher
|
||||||
@@ -92,7 +91,6 @@ public class NativeAESCipherSpi extends CipherSpi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void nCleanup(long ctxPtr);
|
private static native void nCleanup(long ctxPtr);
|
||||||
@@ -155,11 +153,7 @@ public class NativeAESCipherSpi extends CipherSpi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int finalAmt = nFinal(mCtxPtr, mPadding, output, outputOffset + updateAmt, outputSize - updateAmt);
|
int finalAmt = nFinal(mCtxPtr, mPadding, output, outputOffset + updateAmt, outputSize - updateAmt);
|
||||||
|
return updateAmt + finalAmt;
|
||||||
int out = updateAmt + finalAmt;
|
|
||||||
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private native int nFinal(long ctxPtr, boolean usePadding, byte[] output, int outputOffest, int outputSize)
|
private native int nFinal(long ctxPtr, boolean usePadding, byte[] output, int outputOffest, int outputSize)
|
||||||
@@ -231,22 +225,19 @@ public class NativeAESCipherSpi extends CipherSpi {
|
|||||||
} catch (InvalidParameterSpecException e) {
|
} catch (InvalidParameterSpecException e) {
|
||||||
throw new InvalidAlgorithmParameterException(e);
|
throw new InvalidAlgorithmParameterException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(int opmode, Key key, IvParameterSpec params) {
|
private void init(int opmode, Key key, IvParameterSpec params) {
|
||||||
if ( mIsInited ) {
|
if (mIsInit) {
|
||||||
// Do not allow multiple inits
|
// Do not allow multiple inits
|
||||||
assert(true);
|
|
||||||
throw new RuntimeException("Don't allow multiple inits");
|
throw new RuntimeException("Don't allow multiple inits");
|
||||||
} else {
|
} else {
|
||||||
NativeLib.init();
|
NativeLib.INSTANCE.init();
|
||||||
mIsInited = true;
|
mIsInit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mIV = params.getIV();
|
mIV = params.getIV();
|
||||||
mEncrypting = opmode == Cipher.ENCRYPT_MODE;
|
mCtxPtr = nInit(opmode == Cipher.ENCRYPT_MODE, key.getEncoded(), mIV);
|
||||||
mCtxPtr = nInit(mEncrypting, key.getEncoded(), mIV);
|
|
||||||
addToCleanupQueue(this, mCtxPtr);
|
addToCleanupQueue(this, mCtxPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,26 +254,23 @@ public class NativeAESCipherSpi extends CipherSpi {
|
|||||||
protected void engineSetPadding(String padding)
|
protected void engineSetPadding(String padding)
|
||||||
throws NoSuchPaddingException {
|
throws NoSuchPaddingException {
|
||||||
|
|
||||||
if ( ! mIsInited ) {
|
if ( !mIsInit) {
|
||||||
NativeLib.init();
|
NativeLib.INSTANCE.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( padding.length() == 0 ) {
|
if ( padding.length() == 0 ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ( !padding.equals("PKCS5Padding") ) {
|
||||||
if ( ! padding.equals("PKCS5Padding") ) {
|
|
||||||
throw new NoSuchPaddingException("Only supports PKCS5Padding.");
|
throw new NoSuchPaddingException("Only supports PKCS5Padding.");
|
||||||
}
|
}
|
||||||
|
|
||||||
mPadding = true;
|
mPadding = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
|
protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
|
||||||
int maxSize = engineGetOutputSize(inputLen);
|
int maxSize = engineGetOutputSize(inputLen);
|
||||||
byte output[] = new byte[maxSize];
|
byte[] output = new byte[maxSize];
|
||||||
|
|
||||||
int updateSize = update(input, inputOffset, inputLen, output, 0);
|
int updateSize = update(input, inputOffset, inputLen, output, 0);
|
||||||
|
|
||||||
@@ -302,24 +290,15 @@ public class NativeAESCipherSpi extends CipherSpi {
|
|||||||
byte[] output, int outputOffset) throws ShortBufferException {
|
byte[] output, int outputOffset) throws ShortBufferException {
|
||||||
|
|
||||||
int result = update(input, inputOffset, inputLen, output, outputOffset);
|
int result = update(input, inputOffset, inputLen, output, outputOffset);
|
||||||
|
|
||||||
if ( result == -1 ) {
|
if ( result == -1 ) {
|
||||||
throw new ShortBufferException("Insufficient buffer.");
|
throw new ShortBufferException("Insufficient buffer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) {
|
private int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) {
|
||||||
int outputSize = engineGetOutputSize(inputLen);
|
int outputSize = engineGetOutputSize(inputLen);
|
||||||
|
return nUpdate(mCtxPtr, input, inputOffset, inputLen, output, outputOffset, outputSize);
|
||||||
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);
|
private native int nUpdate(long ctxPtr, byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset, int outputSize);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||||
*
|
*
|
||||||
* This file is part of KeePass DX.
|
* This file is part of KeePass DX.
|
||||||
*
|
*
|
||||||
@@ -17,30 +17,30 @@
|
|||||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.crypto;
|
package com.kunzisoft.keepass.crypto
|
||||||
|
|
||||||
public class NativeLib {
|
object NativeLib {
|
||||||
private static boolean isLoaded = false;
|
private var isLoaded = false
|
||||||
private static boolean loadSuccess = false;
|
private var loadSuccess = false
|
||||||
|
|
||||||
public static boolean loaded() {
|
fun loaded(): Boolean {
|
||||||
return init();
|
return init()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean init() {
|
fun init(): Boolean {
|
||||||
if ( ! isLoaded ) {
|
if (!isLoaded) {
|
||||||
try {
|
try {
|
||||||
System.loadLibrary("final-key");
|
System.loadLibrary("final-key")
|
||||||
System.loadLibrary("argon2");
|
System.loadLibrary("argon2")
|
||||||
} catch ( UnsatisfiedLinkError e) {
|
} catch (e: UnsatisfiedLinkError) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
isLoaded = true;
|
|
||||||
loadSuccess = true;
|
isLoaded = true
|
||||||
|
loadSuccess = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadSuccess;
|
return loadSuccess
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.crypto;
|
|
||||||
|
|
||||||
import org.spongycastle.crypto.StreamCipher;
|
|
||||||
import org.spongycastle.crypto.engines.ChaCha7539Engine;
|
|
||||||
import org.spongycastle.crypto.engines.Salsa20Engine;
|
|
||||||
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,
|
|
||||||
(byte)0x97, 0x20, 0x5D, 0x2A };
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
StreamCipher cipher = new Salsa20Engine();
|
|
||||||
cipher.init(true, ivParam);
|
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
StreamCipher cipher = new ChaCha7539Engine();
|
|
||||||
cipher.init(true, ivParam);
|
|
||||||
|
|
||||||
return cipher;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 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.crypto
|
||||||
|
|
||||||
|
import org.spongycastle.crypto.StreamCipher
|
||||||
|
import org.spongycastle.crypto.engines.ChaCha7539Engine
|
||||||
|
import org.spongycastle.crypto.engines.Salsa20Engine
|
||||||
|
import org.spongycastle.crypto.params.KeyParameter
|
||||||
|
import org.spongycastle.crypto.params.ParametersWithIV
|
||||||
|
|
||||||
|
object StreamCipherFactory {
|
||||||
|
|
||||||
|
private val SALSA_IV = byteArrayOf(0xE8.toByte(), 0x30, 0x09, 0x4B, 0x97.toByte(), 0x20, 0x5D, 0x2A)
|
||||||
|
|
||||||
|
fun getInstance(alg: CrsAlgorithm?, key: ByteArray): StreamCipher? {
|
||||||
|
return when {
|
||||||
|
alg === CrsAlgorithm.Salsa20 -> getSalsa20(key)
|
||||||
|
alg === CrsAlgorithm.ChaCha20 -> getChaCha20(key)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSalsa20(key: ByteArray): StreamCipher {
|
||||||
|
// Build stream cipher key
|
||||||
|
val key32 = CryptoUtil.hashSha256(key)
|
||||||
|
|
||||||
|
val keyParam = KeyParameter(key32)
|
||||||
|
val ivParam = ParametersWithIV(keyParam, SALSA_IV)
|
||||||
|
|
||||||
|
val cipher = Salsa20Engine()
|
||||||
|
cipher.init(true, ivParam)
|
||||||
|
|
||||||
|
return cipher
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getChaCha20(key: ByteArray): StreamCipher {
|
||||||
|
// Build stream cipher key
|
||||||
|
val hash = CryptoUtil.hashSha512(key)
|
||||||
|
val key32 = ByteArray(32)
|
||||||
|
val iv = ByteArray(12)
|
||||||
|
|
||||||
|
System.arraycopy(hash, 0, key32, 0, 32)
|
||||||
|
System.arraycopy(hash, 32, iv, 0, 12)
|
||||||
|
|
||||||
|
val keyParam = KeyParameter(key32)
|
||||||
|
val ivParam = ParametersWithIV(keyParam, iv)
|
||||||
|
|
||||||
|
val cipher = ChaCha7539Engine()
|
||||||
|
cipher.init(true, ivParam)
|
||||||
|
|
||||||
|
return cipher
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,12 +27,12 @@ import java.io.IOException;
|
|||||||
public class NativeFinalKey extends FinalKey {
|
public class NativeFinalKey extends FinalKey {
|
||||||
|
|
||||||
public static boolean availble() {
|
public static boolean availble() {
|
||||||
return NativeLib.init();
|
return NativeLib.INSTANCE.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] transformMasterKey(byte[] seed, byte[] key, long rounds) throws IOException {
|
public byte[] transformMasterKey(byte[] seed, byte[] key, long rounds) throws IOException {
|
||||||
NativeLib.init();
|
NativeLib.INSTANCE.init();
|
||||||
|
|
||||||
return nTransformMasterKey(seed, key, rounds);
|
return nTransformMasterKey(seed, key, rounds);
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class Argon2Native {
|
|||||||
public static byte[] transformKey(byte[] password, byte[] salt, int parallelism,
|
public static byte[] transformKey(byte[] password, byte[] salt, int parallelism,
|
||||||
long memory, long iterations, byte[] secretKey,
|
long memory, long iterations, byte[] secretKey,
|
||||||
byte[] associatedData, long version) throws IOException {
|
byte[] associatedData, long version) throws IOException {
|
||||||
NativeLib.init();
|
NativeLib.INSTANCE.init();
|
||||||
|
|
||||||
return nTransformMasterKey(password, salt, parallelism, memory, iterations, secretKey, associatedData, version);
|
return nTransformMasterKey(password, salt, parallelism, memory, iterations, secretKey, associatedData, version);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.database.file.load
|
|||||||
import biz.source_code.base64Coder.Base64Coder
|
import biz.source_code.base64Coder.Base64Coder
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.crypto.CipherFactory
|
import com.kunzisoft.keepass.crypto.CipherFactory
|
||||||
import com.kunzisoft.keepass.crypto.PwStreamCipherFactory
|
import com.kunzisoft.keepass.crypto.StreamCipherFactory
|
||||||
import com.kunzisoft.keepass.crypto.engine.CipherEngine
|
import com.kunzisoft.keepass.crypto.engine.CipherEngine
|
||||||
import com.kunzisoft.keepass.database.file.PwCompressionAlgorithm
|
import com.kunzisoft.keepass.database.file.PwCompressionAlgorithm
|
||||||
import com.kunzisoft.keepass.database.element.*
|
import com.kunzisoft.keepass.database.element.*
|
||||||
@@ -183,7 +183,7 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
|
|||||||
loadInnerHeader(isXml, header)
|
loadInnerHeader(isXml, header)
|
||||||
}
|
}
|
||||||
|
|
||||||
randomStream = PwStreamCipherFactory.getInstance(header.innerRandomStream, header.innerRandomStreamKey)
|
randomStream = StreamCipherFactory.getInstance(header.innerRandomStream, header.innerRandomStreamKey)
|
||||||
|
|
||||||
if (randomStream == null) {
|
if (randomStream == null) {
|
||||||
throw ArcFourException()
|
throw ArcFourException()
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import android.util.Xml
|
|||||||
import biz.source_code.base64Coder.Base64Coder
|
import biz.source_code.base64Coder.Base64Coder
|
||||||
import com.kunzisoft.keepass.crypto.CipherFactory
|
import com.kunzisoft.keepass.crypto.CipherFactory
|
||||||
import com.kunzisoft.keepass.crypto.CrsAlgorithm
|
import com.kunzisoft.keepass.crypto.CrsAlgorithm
|
||||||
import com.kunzisoft.keepass.crypto.PwStreamCipherFactory
|
import com.kunzisoft.keepass.crypto.StreamCipherFactory
|
||||||
import com.kunzisoft.keepass.crypto.engine.CipherEngine
|
import com.kunzisoft.keepass.crypto.engine.CipherEngine
|
||||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
|
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
|
||||||
import com.kunzisoft.keepass.database.*
|
import com.kunzisoft.keepass.database.*
|
||||||
@@ -275,7 +275,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
|
|||||||
}
|
}
|
||||||
random.nextBytes(header.innerRandomStreamKey)
|
random.nextBytes(header.innerRandomStreamKey)
|
||||||
|
|
||||||
randomStream = PwStreamCipherFactory.getInstance(header.innerRandomStream, header.innerRandomStreamKey)
|
randomStream = StreamCipherFactory.getInstance(header.innerRandomStream, header.innerRandomStreamKey)
|
||||||
if (randomStream == null) {
|
if (randomStream == null) {
|
||||||
throw PwDbOutputException("Invalid random cipher")
|
throw PwDbOutputException("Invalid random cipher")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user