From da8808a4b9c17c55f4e9cf5269d0d973e90badf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=8B=D1=82=D0=BA=D0=BE=D0=B2=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD?= Date: Sat, 8 Feb 2025 17:45:13 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D1=82=D0=B0=D1=82=D0=B8=D1=87=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20IV=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D0=BC=D1=91?= =?UTF-8?q?=D0=BD=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/db/app/dao/StorageKeyMapDao.kt | 4 +- .../app/repository/StorageKeyMapRepository.kt | 12 +-- .../wallenc/data/storages/UnlockManager.kt | 13 +++- .../data/storages/encrypt/EncryptedStorage.kt | 34 +++++++-- .../encrypt/EncryptedStorageAccessor.kt | 33 +++++---- .../common/impl/CommonStorageMetaInfo.kt | 5 +- .../domain/datatypes/StorageEncryptionInfo.kt | 24 +++++- .../wallenc/domain/encrypt/Encryptor.kt | 47 ++++++------ .../domain/encrypt/EncryptorWithStaticIv.kt | 73 +++++++++++++++++++ .../wallenc/domain/interfaces/IStorage.kt | 18 +++++ .../wallenc/domain/interfaces/IStorageInfo.kt | 13 ---- .../domain/interfaces/IStorageMetaInfo.kt | 11 --- 12 files changed, 201 insertions(+), 86 deletions(-) create mode 100644 domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptorWithStaticIv.kt delete mode 100644 domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt delete mode 100644 domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageKeyMapDao.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageKeyMapDao.kt index 2bc12e2..22d01d1 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageKeyMapDao.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/dao/StorageKeyMapDao.kt @@ -10,11 +10,11 @@ import com.github.nullptroma.wallenc.data.db.app.model.DbStorageKeyMap @Dao interface StorageKeyMapDao { @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun add(keymap: DbStorageKeyMap) + suspend fun add(vararg keymaps: DbStorageKeyMap) @Query("SELECT * FROM storage_key_maps") suspend fun getAll(): List @Delete - suspend fun delete(keymap: DbStorageKeyMap) + suspend fun delete(vararg keymaps: DbStorageKeyMap) } \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageKeyMapRepository.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageKeyMapRepository.kt index 3efcf3d..31e4fc9 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageKeyMapRepository.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/db/app/repository/StorageKeyMapRepository.kt @@ -11,13 +11,13 @@ class StorageKeyMapRepository( private val ioDispatcher: CoroutineDispatcher ) { suspend fun getAll() = withContext(ioDispatcher) { dao.getAll().map { it.toModel() } } - suspend fun add(keymap: StorageKeyMap) = withContext(ioDispatcher) { - val dbModel = DbStorageKeyMap.fromModel(keymap) - dao.add(dbModel) + suspend fun add(vararg keymaps: StorageKeyMap) = withContext(ioDispatcher) { + val dbModels = keymaps.map { DbStorageKeyMap.fromModel(it) } + dao.add(*dbModels.toTypedArray()) } - suspend fun delete(keymap: StorageKeyMap) = withContext(ioDispatcher) { - val dbModel = DbStorageKeyMap.fromModel(keymap) - dao.delete(dbModel) + suspend fun delete(vararg keymaps: StorageKeyMap) = withContext(ioDispatcher) { + val dbModels = keymaps.map { DbStorageKeyMap.fromModel(it) } + dao.delete(*dbModels.toTypedArray()) } } \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt index 0e60af4..eadd018 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/UnlockManager.kt @@ -36,16 +36,23 @@ class UnlockManager( vaultsManager.allStorages.collectLatest { mutex.lock() val allKeys = keymapRepository.getAll() + val keysToRemove = mutableListOf() val allStorages = it.associateBy({ it.uuid }, { it }) val map = _openedStorages.value?.toMutableMap() ?: mutableMapOf() for(keymap in allKeys) { if(map.contains(keymap.sourceUuid)) continue - val storage = allStorages[keymap.sourceUuid] ?: continue - val encStorage = createEncryptedStorage(storage, keymap.key, keymap.destUuid) - map[storage.uuid] = encStorage + try { + val storage = allStorages[keymap.sourceUuid] ?: continue + val encStorage = createEncryptedStorage(storage, keymap.key, keymap.destUuid) + map[storage.uuid] = encStorage + } + catch (_: Exception) { + keysToRemove.add(keymap) + } } _openedStorages.value = map + keymapRepository.delete(*keysToRemove.toTypedArray()) // удалить мёртвые ключи mutex.unlock() } } diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorage.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorage.kt index d8e9bab..d3a3e14 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorage.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorage.kt @@ -4,10 +4,13 @@ import com.github.nullptroma.wallenc.data.db.app.repository.StorageMetaInfoRepos import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo +import com.github.nullptroma.wallenc.domain.encrypt.Encryptor import com.github.nullptroma.wallenc.domain.interfaces.IStorage import com.github.nullptroma.wallenc.domain.interfaces.IStorageMetaInfo import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.withContext @@ -15,11 +18,15 @@ import java.util.UUID class EncryptedStorage private constructor( private val source: IStorage, - key: EncryptKey, - private val ioDispatcher: CoroutineDispatcher, + private val key: EncryptKey, + ioDispatcher: CoroutineDispatcher, private val metaInfoProvider: StorageMetaInfoRepository.SingleStorageMetaInfoProvider, override val uuid: UUID = UUID.randomUUID() ) : IStorage, DisposableHandle { + private val job = Job() + private val scope = CoroutineScope(ioDispatcher + job) + private val encInfo = source.metaInfo.value.encInfo ?: throw Exception("Storage is not encrypted") // TODO + override val size: StateFlow get() = source.size override val numberOfFiles: StateFlow @@ -35,13 +42,19 @@ class EncryptedStorage private constructor( override val isAvailable: StateFlow get() = source.isAvailable override val accessor: EncryptedStorageAccessor = - EncryptedStorageAccessor(source.accessor, key, ioDispatcher) + EncryptedStorageAccessor(source.accessor, encInfo.pathIv, key, scope) private suspend fun init() { + checkKey() readMeta() } - private suspend fun readMeta() = withContext(ioDispatcher) { + private fun checkKey() { + if(!Encryptor.checkKey(key, encInfo)) + throw Exception("Incorrect key") // TODO + } + + private suspend fun readMeta() = scope.run { var meta = metaInfoProvider.get() if(meta == null) { meta = CommonStorageMetaInfo() @@ -50,7 +63,7 @@ class EncryptedStorage private constructor( _metaInfo.value = meta } - override suspend fun rename(newName: String) = withContext(ioDispatcher) { + override suspend fun rename(newName: String) = scope.run { val cur = _metaInfo.value val newMeta = CommonStorageMetaInfo( encInfo = cur.encInfo, @@ -60,7 +73,7 @@ class EncryptedStorage private constructor( metaInfoProvider.set(newMeta) } - override suspend fun setEncInfo(encInfo: StorageEncryptionInfo) = withContext(ioDispatcher) { + override suspend fun setEncInfo(encInfo: StorageEncryptionInfo) = scope.run { val cur = _metaInfo.value val newMeta = CommonStorageMetaInfo( encInfo = encInfo, @@ -72,6 +85,7 @@ class EncryptedStorage private constructor( override fun dispose() { accessor.dispose() + job.cancel() } companion object { @@ -89,7 +103,13 @@ class EncryptedStorage private constructor( metaInfoProvider = metaInfoProvider, uuid = uuid ) - storage.init() + try { + storage.init() + } + catch (e: Exception) { + storage.dispose() + throw e + } return@withContext storage } } diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorageAccessor.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorageAccessor.kt index 724f660..383f4fa 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorageAccessor.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/storages/encrypt/EncryptedStorageAccessor.kt @@ -1,19 +1,19 @@ package com.github.nullptroma.wallenc.data.storages.encrypt +import android.util.Log import com.github.nullptroma.wallenc.domain.common.impl.CommonDirectory import com.github.nullptroma.wallenc.domain.common.impl.CommonFile import com.github.nullptroma.wallenc.domain.common.impl.CommonMetaInfo import com.github.nullptroma.wallenc.domain.datatypes.DataPackage import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey import com.github.nullptroma.wallenc.domain.encrypt.Encryptor +import com.github.nullptroma.wallenc.domain.encrypt.EncryptorWithStaticIv import com.github.nullptroma.wallenc.domain.interfaces.IDirectory import com.github.nullptroma.wallenc.domain.interfaces.IFile import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DisposableHandle -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow @@ -27,12 +27,10 @@ import kotlin.io.path.pathString class EncryptedStorageAccessor( private val source: IStorageAccessor, + pathIv: ByteArray, key: EncryptKey, - ioDispatcher: CoroutineDispatcher + private val scope: CoroutineScope ) : IStorageAccessor, DisposableHandle { - private val job = Job() - private val scope = CoroutineScope(ioDispatcher + job) - override val size: StateFlow = source.size override val numberOfFiles: StateFlow = source.numberOfFiles override val isAvailable: StateFlow = source.isAvailable @@ -43,10 +41,19 @@ class EncryptedStorageAccessor( private val _dirsUpdates = MutableSharedFlow>>() override val dirsUpdates: SharedFlow>> = _dirsUpdates - private val encryptor = Encryptor(key.toAesKey()) + private val dataEncryptor = Encryptor(key.toAesKey()) + private val pathEncryptor = EncryptorWithStaticIv(key.toAesKey(), pathIv) init { collectSourceState() + + for(i in 1..5) { + val orig = "/hello/path/test.txt" + val enc = encryptPath(orig) + val dec = decryptPath(enc) + + Log.d("MyTag", "Path $orig to $enc to $dec") + } } private fun collectSourceState() { @@ -63,7 +70,6 @@ class EncryptedStorageAccessor( } launch { - source.dirsUpdates.collect { val dirs = it.data.map(::decryptEntity) _dirsUpdates.emit(DataPackage( @@ -116,7 +122,7 @@ class EncryptedStorageAccessor( val path = Path(pathStr) val segments = mutableListOf() for (segment in path) - segments.add(encryptor.encryptString(segment.pathString)) + segments.add(pathEncryptor.encryptString(segment.pathString)) val res = Path("/",*(segments.toTypedArray())) return res.pathString } @@ -125,7 +131,7 @@ class EncryptedStorageAccessor( val path = Path(pathStr) val segments = mutableListOf() for (segment in path) - segments.add(encryptor.decryptString(segment.pathString)) + segments.add(pathEncryptor.decryptString(segment.pathString)) val res = Path("/",*(segments.toTypedArray())) return res.pathString } @@ -198,12 +204,12 @@ class EncryptedStorageAccessor( override suspend fun openWrite(path: String): OutputStream { val stream = source.openWrite(encryptPath(path)) - return encryptor.encryptStream(stream) + return dataEncryptor.encryptStream(stream) } override suspend fun openRead(path: String): InputStream { val stream = source.openRead(encryptPath(path)) - return encryptor.decryptStream(stream) + return dataEncryptor.decryptStream(stream) } override suspend fun moveToTrash(path: String) { @@ -211,8 +217,7 @@ class EncryptedStorageAccessor( } override fun dispose() { - job.cancel() - encryptor.dispose() + dataEncryptor.dispose() } } \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt index f99270d..f5c69ba 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt @@ -9,10 +9,7 @@ import java.time.Instant data class CommonStorageMetaInfo( - override val encInfo: StorageEncryptionInfo = StorageEncryptionInfo( - isEncrypted = false, - encryptedTestData = null - ), + override val encInfo: StorageEncryptionInfo? = null, override val name: String? = null, override val lastModified: Instant = Clock.systemUTC().instant() ) : IStorageMetaInfo \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/StorageEncryptionInfo.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/StorageEncryptionInfo.kt index 38f88ee..cb83099 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/StorageEncryptionInfo.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/StorageEncryptionInfo.kt @@ -1,6 +1,24 @@ package com.github.nullptroma.wallenc.domain.datatypes data class StorageEncryptionInfo( - val isEncrypted: Boolean, - val encryptedTestData: String? -) \ No newline at end of file + val encryptedTestData: String, + val pathIv: ByteArray +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as StorageEncryptionInfo + + if (encryptedTestData != other.encryptedTestData) return false + if (!pathIv.contentEquals(other.pathIv)) return false + + return true + } + + override fun hashCode(): Int { + var result = encryptedTestData.hashCode() + result = 31 * result + pathIv.contentHashCode() + return result + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/Encryptor.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/Encryptor.kt index 52a7803..6bf8244 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/Encryptor.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/Encryptor.kt @@ -14,7 +14,7 @@ import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi import kotlin.random.Random -class Encryptor(private var _secretKey: SecretKey?) : DisposableHandle { +class Encryptor(private var secretKey: SecretKey) : DisposableHandle { @OptIn(ExperimentalEncodingApi::class) fun encryptString(str: String): String { val bytesToEncrypt = str.toByteArray(Charsets.UTF_8) @@ -30,54 +30,57 @@ class Encryptor(private var _secretKey: SecretKey?) : DisposableHandle { } fun encryptBytes(bytes: ByteArray): ByteArray { - val secretKey = _secretKey ?: throw Exception("Object was disposed") + if(secretKey.isDestroyed) + throw Exception("Object was destroyed") val cipher = Cipher.getInstance(AES_SETTINGS) - val iv = IvParameterSpec(Random.nextBytes(IV_LEN)) - cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv) - val encryptedBytes = iv.iv + cipher.doFinal(bytes) // iv + зашифрованные байты + val ivSpec = IvParameterSpec(Random.nextBytes(IV_LEN)) + cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec) + val encryptedBytes = ivSpec.iv + cipher.doFinal(bytes) // iv + зашифрованные байты return encryptedBytes } fun decryptBytes(bytes: ByteArray): ByteArray { - val secretKey = _secretKey ?: throw Exception("Object was disposed") + if(secretKey.isDestroyed) + throw Exception("Object was destroyed") val cipher = Cipher.getInstance(AES_SETTINGS) - val iv = IvParameterSpec(bytes.take(IV_LEN).toByteArray()) - cipher.init(Cipher.DECRYPT_MODE, secretKey, iv) + val ivSpec = IvParameterSpec(bytes.take(IV_LEN).toByteArray()) + cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec) val decryptedBytes = cipher.doFinal(bytes.drop(IV_LEN).toByteArray()) return decryptedBytes } fun encryptStream(stream: OutputStream): OutputStream { - val secretKey = _secretKey ?: throw Exception("Object was disposed") - val iv = IvParameterSpec(Random.nextBytes(IV_LEN)) - stream.write(iv.iv) // Запись инициализационного вектора сырой файл + if(secretKey.isDestroyed) + throw Exception("Object was destroyed") + val ivSpec = IvParameterSpec(Random.nextBytes(IV_LEN)) + stream.write(ivSpec.iv) // Запись инициализационного вектора сырой файл val cipher = Cipher.getInstance(AES_SETTINGS) - cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv) // инициализация шифратора + cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec) // инициализация шифратора return CipherOutputStream(stream, cipher) } fun decryptStream(stream: InputStream): InputStream { - val secretKey = _secretKey ?: throw Exception("Object was disposed") + if(secretKey.isDestroyed) + throw Exception("Object was destroyed") val ivBytes = ByteArray(IV_LEN) // Буфер для 16 байт IV val bytesRead = stream.read(ivBytes) // Чтение IV вектора if(bytesRead != IV_LEN) throw Exception("TODO iv не прочитан") - val iv = IvParameterSpec(ivBytes) + val ivSpec = IvParameterSpec(ivBytes) val cipher = Cipher.getInstance(AES_SETTINGS) - cipher.init(Cipher.DECRYPT_MODE, secretKey, iv) + cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec) return CipherInputStream(stream, cipher) } override fun dispose() { - _secretKey?.destroy() - _secretKey = null + secretKey.destroy() } companion object { - private const val IV_LEN = 16 + public const val IV_LEN = 16 + public const val AES_SETTINGS = "AES/CBC/PKCS5Padding" private const val TEST_DATA_LEN = 512 - private const val AES_SETTINGS = "AES/CBC/PKCS5Padding" @OptIn(ExperimentalEncodingApi::class) fun generateEncryptionInfo(key: EncryptKey) : StorageEncryptionInfo { @@ -85,15 +88,13 @@ class Encryptor(private var _secretKey: SecretKey?) : DisposableHandle { val testData = ByteArray(TEST_DATA_LEN) val encryptedData = encryptor.encryptBytes(testData) return StorageEncryptionInfo( - isEncrypted = true, - encryptedTestData = Base64.Default.encode(encryptedData) + encryptedTestData = Base64.Default.encode(encryptedData), + pathIv = Random.nextBytes(IV_LEN) ) } @OptIn(ExperimentalEncodingApi::class) fun checkKey(key: EncryptKey, encInfo: StorageEncryptionInfo): Boolean { - if(encInfo.encryptedTestData == null) - return false val encryptor = Encryptor(key.toAesKey()) try { val encData = Base64.Default.decode(encInfo.encryptedTestData) diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptorWithStaticIv.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptorWithStaticIv.kt new file mode 100644 index 0000000..c6fa9e9 --- /dev/null +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptorWithStaticIv.kt @@ -0,0 +1,73 @@ +package com.github.nullptroma.wallenc.domain.encrypt + +import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey +import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo +import com.github.nullptroma.wallenc.domain.encrypt.Encryptor.Companion.AES_SETTINGS +import com.github.nullptroma.wallenc.domain.encrypt.Encryptor.Companion.IV_LEN +import kotlinx.coroutines.DisposableHandle +import java.io.InputStream +import java.io.OutputStream +import javax.crypto.Cipher +import javax.crypto.CipherInputStream +import javax.crypto.CipherOutputStream +import javax.crypto.SecretKey +import javax.crypto.spec.IvParameterSpec +import kotlin.io.encoding.Base64 +import kotlin.io.encoding.ExperimentalEncodingApi +import kotlin.random.Random + +class EncryptorWithStaticIv(private var secretKey: SecretKey, iv: ByteArray) : DisposableHandle { + private val ivSpec = IvParameterSpec(iv) + + @OptIn(ExperimentalEncodingApi::class) + fun encryptString(str: String): String { + val bytesToEncrypt = str.toByteArray(Charsets.UTF_8) + val encryptedBytes = encryptBytes(bytesToEncrypt) + return Base64.Default.encode(encryptedBytes).replace("/", ".") + } + + @OptIn(ExperimentalEncodingApi::class) + fun decryptString(str: String): String { + val bytesToDecrypt = Base64.Default.decode(str.replace(".", "/")) + val decryptedBytes = decryptBytes(bytesToDecrypt) + return String(decryptedBytes, Charsets.UTF_8) + } + + fun encryptBytes(bytes: ByteArray): ByteArray { + if(secretKey.isDestroyed) + throw Exception("Object was destroyed") + val cipher = Cipher.getInstance(AES_SETTINGS) + cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec) + val encryptedBytes = cipher.doFinal(bytes) // зашифрованные байты + return encryptedBytes + } + + fun decryptBytes(bytes: ByteArray): ByteArray { + if(secretKey.isDestroyed) + throw Exception("Object was destroyed") + val cipher = Cipher.getInstance(AES_SETTINGS) + cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec) + val decryptedBytes = cipher.doFinal(bytes) + return decryptedBytes + } + + fun encryptStream(stream: OutputStream): OutputStream { + if(secretKey.isDestroyed) + throw Exception("Object was destroyed") + val cipher = Cipher.getInstance(AES_SETTINGS) + cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec) // инициализация шифратора + return CipherOutputStream(stream, cipher) + } + + fun decryptStream(stream: InputStream): InputStream { + if(secretKey.isDestroyed) + throw Exception("Object was destroyed") + val cipher = Cipher.getInstance(AES_SETTINGS) + cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec) + return CipherInputStream(stream, cipher) + } + + override fun dispose() { + secretKey.destroy() + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorage.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorage.kt index 3fb0630..cc6815a 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorage.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorage.kt @@ -1,6 +1,18 @@ package com.github.nullptroma.wallenc.domain.interfaces import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo +import kotlinx.coroutines.flow.StateFlow +import java.time.Instant +import java.util.UUID + +sealed interface IStorageInfo { + val uuid: UUID + val isAvailable: StateFlow + val size: StateFlow + val numberOfFiles: StateFlow + val metaInfo: StateFlow + val isVirtualStorage: Boolean +} interface IStorage: IStorageInfo { val accessor: IStorageAccessor @@ -8,3 +20,9 @@ interface IStorage: IStorageInfo { suspend fun rename(newName: String) suspend fun setEncInfo(encInfo: StorageEncryptionInfo) } + +interface IStorageMetaInfo { + val encInfo: StorageEncryptionInfo? + val name: String? + val lastModified: Instant +} diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt deleted file mode 100644 index dec9aad..0000000 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.github.nullptroma.wallenc.domain.interfaces - -import kotlinx.coroutines.flow.StateFlow -import java.util.UUID - -sealed interface IStorageInfo { - val uuid: UUID - val isAvailable: StateFlow - val size: StateFlow - val numberOfFiles: StateFlow - val metaInfo: StateFlow - val isVirtualStorage: Boolean -} \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt deleted file mode 100644 index 27766ab..0000000 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.nullptroma.wallenc.domain.interfaces - -import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo -import java.time.Instant - -interface IStorageMetaInfo { - val encInfo: StorageEncryptionInfo - val name: String? - val lastModified: Instant - -} \ No newline at end of file