All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jetbrains.exodus.crypto.EncryptedBlobVault.kt Maven / Gradle / Ivy

There is a newer version: 9.8.0.76914
Show newest version
/**
 * Copyright 2010 - 2022 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrains.exodus.crypto

import jetbrains.exodus.core.dataStructures.hash.LongHashMap
import jetbrains.exodus.core.dataStructures.hash.LongSet
import jetbrains.exodus.entitystore.BlobVault
import jetbrains.exodus.entitystore.BlobVaultItem
import jetbrains.exodus.entitystore.DiskBasedBlobVault
import jetbrains.exodus.entitystore.FileSystemBlobVaultOld
import jetbrains.exodus.env.Transaction
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.io.OutputStream

class EncryptedBlobVault(private val decorated: FileSystemBlobVaultOld,
                         private val cipherProvider: StreamCipherProvider,
                         private val cipherKey: ByteArray,
                         private val cipherBasicIV: Long) : BlobVault(decorated), DiskBasedBlobVault {

    override fun getSourceVault() = decorated

    override fun clear() = decorated.clear()

    override fun getBackupStrategy() = decorated.backupStrategy

    override fun getBlob(blobHandle: Long): BlobVaultItem {
        return decorated.getBlob(blobHandle)
    }

    override fun getContent(blobHandle: Long, txn: Transaction): InputStream? {
        return decorated.getContent(blobHandle, txn)?.run {
            StreamCipherInputStream(this) {
                newCipher(blobHandle)
            }
        }
    }

    override fun delete(blobHandle: Long): Boolean {
        return decorated.delete(blobHandle)
    }

    override fun getBlobLocation(blobHandle: Long): File {
        return decorated.getBlobLocation(blobHandle)
    }

    override fun getBlobLocation(blobHandle: Long, readonly: Boolean): File {
        return decorated.getBlobLocation(blobHandle, readonly)
    }

    override fun getBlobKey(blobHandle: Long): String {
        return decorated.getBlobKey(blobHandle)
    }

    override fun getSize(blobHandle: Long, txn: Transaction) = decorated.getSize(blobHandle, txn)

    override fun requiresTxn() = decorated.requiresTxn()

    override fun flushBlobs(blobStreams: LongHashMap?,
                            blobFiles: LongHashMap?,
                            deferredBlobsToDelete: LongSet?,
                            txn: Transaction) {
        val streams = LongHashMap()
        blobStreams?.forEach {
            streams[it.key] = StreamCipherInputStream(it.value) {
                newCipher(it.key)
            }
        }
        var openFiles: MutableList? = null
        try {
            if (blobFiles != null && blobFiles.isNotEmpty()) {
                openFiles = mutableListOf()
                blobFiles.forEach {
                    streams[it.key] = StreamCipherInputStream(
                            FileInputStream(it.value)
                                    .also { openFiles.add(it) }
                                    .asBuffered
                                    .apply { mark(Int.MAX_VALUE) }
                    ) {
                        newCipher(it.key)
                    }
                }
            }
            decorated.flushBlobs(streams, null, deferredBlobsToDelete, txn)
        } finally {
            openFiles?.forEach { it.close() }
        }
    }

    override fun size() = decorated.size()

    override fun nextHandle(txn: Transaction) = decorated.nextHandle(txn)

    override fun close() = decorated.close()

    fun wrapOutputStream(blobHandle: Long, output: OutputStream): StreamCipherOutputStream {
        return StreamCipherOutputStream(output, newCipher(blobHandle))
    }

    private fun newCipher(blobHandle: Long) =
            cipherProvider.newCipher().apply { init(cipherKey, (cipherBasicIV - blobHandle).asHashedIV()) }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy