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

net.java.truevfs.driver.zip.raes.ZipRaesDriver Maven / Gradle / Ivy

Go to download

Provides a file system driver for accessing the RAES encrypted ZIP file format, alias ZIP.RAES or TZP. Add the JAR artifact of this module to the run time class path to make its file system drivers available for service location in the client API modules.

There is a newer version: 0.14.0
Show newest version
/*
 * Copyright (C) 2005-2015 Schlichtherle IT Services.
 * All rights reserved. Use is subject to license terms.
 */
package net.java.truevfs.driver.zip.raes;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.SeekableByteChannel;
import javax.annotation.CheckForNull;
import javax.annotation.WillNotClose;
import javax.annotation.concurrent.Immutable;
import net.java.truecommons.cio.Entry;
import net.java.truecommons.cio.Entry.Type;
import net.java.truecommons.cio.InputService;
import net.java.truecommons.cio.OutputService;
import net.java.truecommons.shed.BitField;
import net.java.truevfs.comp.zipdriver.JarDriver;
import net.java.truevfs.comp.zipdriver.JarDriverEntry;
import net.java.truevfs.comp.zipdriver.ZipInputService;
import net.java.truevfs.comp.zipdriver.ZipOutputService;
import net.java.truevfs.driver.zip.raes.crypto.RaesOutputStream;
import net.java.truevfs.driver.zip.raes.crypto.RaesParameters;
import net.java.truevfs.driver.zip.raes.crypto.RaesReadOnlyChannel;
import net.java.truevfs.kernel.spec.FsAccessOption;
import static net.java.truevfs.kernel.spec.FsAccessOption.*;
import net.java.truevfs.kernel.spec.FsController;
import net.java.truevfs.kernel.spec.FsInputSocketSource;
import net.java.truevfs.kernel.spec.FsModel;
import net.java.truevfs.kernel.spec.FsNodeName;
import net.java.truevfs.kernel.spec.FsOutputSocketSink;
import net.java.truevfs.kernel.spec.cio.MultiplexingOutputService;

/**
 * An abstract archive driver for RAES encrypted ZIP files which optionally
 * authenticates the cipher data of the input archive files presented to it.
 * 

* Sub-classes must be thread-safe and should be immutable! * * @author Christian Schlichtherle */ @Immutable public abstract class ZipRaesDriver extends JarDriver { /** * {@inheritDoc} *

* The implementation in the class {@link ZipRaesDriver} returns * {@code true} for future use. * * @return {@code true} */ @Override public final boolean getPreambled() { return true; } /** * Returns the RAES parameters for the given file system model. *

* The implementation in the class {@link ZipRaesDriver} returns * {@code new KeyManagerRaesParameters(getKeyManagerMap().getKeyManager(AesPbeParameters.class), mountPointUri(model))}. * * @param model the file system model. * @return The RAES parameters for the given file system model. */ protected RaesParameters raesParameters(FsModel model) { return new KeyManagerRaesParameters(getKeyManagerMap(), mountPointUri(model)); } /** * Returns the value of the property {@code authenticationTrigger}. *

* If the cipher text length of an input RAES file is smaller than or equal * to this value, then the Hash-based Message Authentication Code (HMAC) * for the entire cipher text is computed and verified in order to * authenticate the input RAES file. *

* Otherwise, if the cipher text length of an input RAES file is greater * than this value, then initially only the cipher key and the cipher text * length getKeyManager authenticated. * In addition, whenever an entry is subsequently accessed, then it's * CRC-32 value is checked. *

* Consequently, if the value of this property is set to a negative value, * then the entire cipher text gets never authenticated (CRC-32 * checking only), and if set to {@link Long#MAX_VALUE}, then the entire * cipher text gets always authenticated (no CRC-32 checking). * * @return The value of the property {@code authenticationTrigger}. */ protected abstract long getAuthenticationTrigger(); @Override public final boolean check(JarDriverEntry local, ZipInputService input) { // Optimization: If the cipher text alias the encrypted ZIP file is // smaller than the authentication trigger, then its entire cipher text // has already been authenticated by {@link ZipRaesDriver#zipInput}. // Hence, checking the CRC-32 value of the entry is redundant. return input.length() > getAuthenticationTrigger(); } /** * {@inheritDoc} *

* The implementation in the class {@link ZipRaesDriver} decorates the given controller with a package private * controller which keeps track of the AES PBE parameters, e.g. the encryption passwords. * This method should be overridden in order to return just {@code controller} if and only if you are overriding * {@link #raesParameters(FsModel)}, too, and do not want to use a locatable key manager to resolve * passwords for RAES encryption. */ @Override public FsController decorate(FsController controller) { return new ZipRaesKeyController(controller, this); } @Override protected ZipInputService newZipInput( final FsModel model, final FsInputSocketSource source) throws IOException { final class Source extends FsInputSocketSource { Source() { super(source); } @Override public SeekableByteChannel channel() throws IOException { final RaesReadOnlyChannel channel = RaesReadOnlyChannel .create(raesParameters(model), source); try { if (channel.size() <= getAuthenticationTrigger()) channel.authenticate(); return channel; } catch (final Throwable ex) { try { channel.close(); } catch (final IOException ex2) { ex.addSuppressed(ex2); } throw ex; } } } return new ZipInputService<>(model, new Source(), this); } @Override protected OutputService newOutput( final FsModel model, final FsOutputSocketSink sink, final @CheckForNull @WillNotClose InputService input) throws IOException { final ZipInputService zis = (ZipInputService) input; return new MultiplexingOutputService<>(getPool(), new ZipOutputService<>(model, new RaesSocketSink(model, sink), zis, this)); } @SuppressWarnings("PackageVisibleInnerClass") final class RaesSocketSink extends FsOutputSocketSink { private final FsModel model; private final FsOutputSocketSink sink; RaesSocketSink(final FsModel model, final FsOutputSocketSink sink) { super(sink); this.model = model; this.sink = sink; } @Override public OutputStream stream() throws IOException { return RaesOutputStream.create(raesParameters(model), sink); } @Override public SeekableByteChannel channel() throws IOException { throw new UnsupportedOperationException(); } } /** * Sets {@link FsAccessOption#STORE} in {@code options} before * forwarding the call to {@code controller}. */ @Override protected final FsOutputSocketSink sink( BitField options, final FsController controller, final FsNodeName name) { // Leave FsAccessOption.COMPRESS untouched - the driver shall be given // opportunity to apply its own preferences to sort out such a conflict. options = options.set(STORE); // The RAES file format cannot support GROWing. options = options.clear(GROW); return new FsOutputSocketSink(options, controller.output(options, name, null)); } /** * Returns a new {@link JarDriverEntry}, requesting that the data gets * {@code DEFLATED} if no template is provided. * This feature strengthens the security level of the authentication * process and inhibits the use of an unencrypted temporary I/O entry * (usually a temporary file) in case the sink is not copied from a file * system entry as its input. *

* Furthermore, the method {@link JarDriverEntry#clearEncryption()} is * called in order to prevent adding a redundant encryption layer for the * individual ZIP entry because this would confuse users, increase the size * of the resulting archive file and unecessarily heat the CPU. */ @Override public JarDriverEntry newEntry( final BitField options, final String name, final Type type, final @CheckForNull Entry template) { final JarDriverEntry entry = super.newEntry(options.set(COMPRESS), name, type, template); // Fix for http://java.net/jira/browse/TRUEZIP-176 : // Entry level encryption is enabled if make.getKeyManager(ENCRYPTED) is true // OR template is an instance of ZipEntry // AND ((ZipEntry) template).isEncrypted() is true. // Now switch off entry level encryption because encryption is already // provided by the RAES wrapper file format. entry.clearEncryption(); return entry; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy