package freenet.support.io; import java.io.IOException; import java.security.GeneralSecurityException; import freenet.crypt.EncryptedRandomAccessBuffer; import freenet.crypt.MasterSecret; import freenet.support.Logger; import freenet.support.api.LockableRandomAccessBuffer; import freenet.support.api.LockableRandomAccessBufferFactory; /** Wraps another LockableRandomAccessBufferFactory to enable encryption if currently turned on. */ public class MaybeEncryptedRandomAccessBufferFactory implements LockableRandomAccessBufferFactory { public MaybeEncryptedRandomAccessBufferFactory(LockableRandomAccessBufferFactory factory, boolean encrypt) { this.factory = factory; this.reallyEncrypt = encrypt; } private final LockableRandomAccessBufferFactory factory; private volatile boolean reallyEncrypt; private MasterSecret secret; private static volatile boolean logMINOR; static { Logger.registerClass(MaybeEncryptedRandomAccessBufferFactory.class); } @Override public LockableRandomAccessBuffer makeRAF(long size) throws IOException { long realSize = size; long paddedSize = size; MasterSecret secret = null; synchronized(this) { if(reallyEncrypt && this.secret != null) { secret = this.secret; realSize += TempBucketFactory.CRYPT_TYPE.headerLen; paddedSize = PaddedEphemerallyEncryptedBucket.paddedLength(realSize, PaddedEphemerallyEncryptedBucket.MIN_PADDED_SIZE); if(logMINOR) Logger.minor(this, "Encrypting and padding "+size+" to "+paddedSize); } } LockableRandomAccessBuffer raf = factory.makeRAF(paddedSize); if(secret != null) { if(realSize != paddedSize) raf = new PaddedRandomAccessBuffer(raf, realSize); try { raf = new EncryptedRandomAccessBuffer(TempBucketFactory.CRYPT_TYPE, raf, secret, true); } catch (GeneralSecurityException e) { Logger.error(this, "Cannot create encrypted tempfile: "+e, e); } } return raf; } @Override public LockableRandomAccessBuffer makeRAF(byte[] initialContents, int offset, int size, boolean readOnly) throws IOException { boolean reallyEncrypt = false; synchronized(this) { reallyEncrypt = this.reallyEncrypt; } if(reallyEncrypt) { // FIXME do the encryption in memory? Test it ... LockableRandomAccessBuffer ret = makeRAF(size); ret.pwrite(0, initialContents, offset, size); if(readOnly) ret = new ReadOnlyRandomAccessBuffer(ret); return ret; } else { return factory.makeRAF(initialContents, offset, size, readOnly); } } public void setMasterSecret(MasterSecret secret) { synchronized(this) { this.secret = secret; } } public void setEncryption(boolean value) { synchronized(this) { reallyEncrypt = value; } if(factory instanceof PooledFileRandomAccessBufferFactory) ((PooledFileRandomAccessBufferFactory)factory).enableCrypto(value); } }