Search in sources :

Example 1 with FileHeader

use of org.cryptomator.cryptolib.api.FileHeader in project cryptomator by cryptomator.

the class UpgradeVersion4to5 method migrate.

@SuppressWarnings("deprecation")
private void migrate(Path file, BasicFileAttributes attrs, Cryptor cryptor) throws IOException {
    LOG.info("Starting migration of {}...", file);
    try (FileChannel ch = FileChannel.open(file, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
        // read header:
        ByteBuffer headerBuf = ByteBuffer.allocate(cryptor.fileHeaderCryptor().headerSize());
        ch.read(headerBuf);
        headerBuf.flip();
        LOG.info("\tHeader read");
        FileHeader header = cryptor.fileHeaderCryptor().decryptHeader(headerBuf);
        long cleartextSize = header.getFilesize();
        if (cleartextSize < 0) {
            LOG.info("\tSkipping already migrated file");
            return;
        } else if (cleartextSize > attrs.size()) {
            LOG.warn("\tSkipping file with invalid file size {}/{}", cleartextSize, attrs.size());
            return;
        }
        int headerSize = cryptor.fileHeaderCryptor().headerSize();
        int ciphertextChunkSize = cryptor.fileContentCryptor().ciphertextChunkSize();
        int cleartextChunkSize = cryptor.fileContentCryptor().cleartextChunkSize();
        long newCiphertextSize = Cryptors.ciphertextSize(cleartextSize, cryptor);
        long newEOF = headerSize + newCiphertextSize;
        // int-truncation
        long newFullChunks = newCiphertextSize / ciphertextChunkSize;
        long newAdditionalCiphertextBytes = newCiphertextSize % ciphertextChunkSize;
        if (newAdditionalCiphertextBytes == 0) {
            // (new) last block is already correct. just truncate:
            LOG.info("\tMigrating cleartext size {}: Truncating to new ciphertext size: {}", cleartextSize, newEOF);
            ch.truncate(newEOF);
            LOG.info("\tFile truncated");
        } else {
            // last block may contain padding and needs to be re-encrypted:
            long lastChunkIdx = newFullChunks;
            LOG.info("\tMigrating cleartext size {}: Re-encrypting chunk {}. New ciphertext size: {}", cleartextSize, lastChunkIdx, newEOF);
            long beginOfLastChunk = headerSize + lastChunkIdx * ciphertextChunkSize;
            assert beginOfLastChunk < newEOF;
            int lastCleartextChunkLength = (int) (cleartextSize % cleartextChunkSize);
            assert lastCleartextChunkLength < cleartextChunkSize;
            assert lastCleartextChunkLength > 0;
            ch.position(beginOfLastChunk);
            ByteBuffer lastCiphertextChunk = ByteBuffer.allocate(ciphertextChunkSize);
            int read = ch.read(lastCiphertextChunk);
            if (read != -1) {
                lastCiphertextChunk.flip();
                ByteBuffer lastCleartextChunk = cryptor.fileContentCryptor().decryptChunk(lastCiphertextChunk, lastChunkIdx, header, true);
                lastCleartextChunk.position(0).limit(lastCleartextChunkLength);
                assert lastCleartextChunk.remaining() == lastCleartextChunkLength;
                ByteBuffer newLastChunkCiphertext = cryptor.fileContentCryptor().encryptChunk(lastCleartextChunk, lastChunkIdx, header);
                ch.truncate(beginOfLastChunk);
                ch.write(newLastChunkCiphertext);
            } else {
                LOG.error("\tReached EOF at position {}/{}", beginOfLastChunk, newEOF);
                // must exit method before changing header!
                return;
            }
            LOG.info("\tReencrypted last block");
        }
        header.setFilesize(-1l);
        ByteBuffer newHeaderBuf = cryptor.fileHeaderCryptor().encryptHeader(header);
        ch.position(0);
        ch.write(newHeaderBuf);
        LOG.info("\tUpdated header");
    }
    LOG.info("Finished migration of {}.", file);
}
Also used : FileChannel(java.nio.channels.FileChannel) ByteBuffer(java.nio.ByteBuffer) FileHeader(org.cryptomator.cryptolib.api.FileHeader)

Aggregations

ByteBuffer (java.nio.ByteBuffer)1 FileChannel (java.nio.channels.FileChannel)1 FileHeader (org.cryptomator.cryptolib.api.FileHeader)1