Package freenet.crypt

Source Code of freenet.crypt.EncryptingIoAdapter

package freenet.crypt;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;

import com.db4o.ext.Db4oIOException;
import com.db4o.io.IoAdapter;

import freenet.crypt.ciphers.Rijndael;
import freenet.node.MasterKeys;
import freenet.support.Fields;
import freenet.support.io.FileUtil;

/**
* IoAdapter proxy using Rijndael (256 bit key, 256 bit block) in CTR mode.
* @author Matthew Toseland <toad@amphibian.dyndns.org> (0xE43DA450)
*
* FIXME: URGENT CRYPTO CODE REVIEW!!!
*
* FIXME CRYPTO first problem with this is key = IV. We should pass a separate IV in.
*/
public class EncryptingIoAdapter extends IoAdapter {
 
  private final IoAdapter baseAdapter;
  private final Random random;
  private final byte[] key;
  private final BlockCipher cipher;
  private long position;
  private byte[] blockOutput;
  private long blockPosition;
 
  static final int BLOCK_SIZE_BYTES = 32;

  /**
   * @param baseAdapter2
   * @param databaseKey This is copied, so caller must wipe it.
   * @param random
   */
  public EncryptingIoAdapter(IoAdapter baseAdapter2, byte[] databaseKey, Random random) {
    this.baseAdapter = baseAdapter2;
    this.key = databaseKey.clone();
    this.random = random;
    position = 0;
    blockPosition = -1;
    blockOutput = new byte[32];
    try {
      cipher = new Rijndael(256, 256);
    } catch (UnsupportedCipherException e) {
      throw new Error(e);
    }
    cipher.initialize(databaseKey);
  }

  @Override
  public void close() throws Db4oIOException {
    baseAdapter.close();
    synchronized(this) {
      MasterKeys.clear(key);
    }
  }

  @Override
  public void delete(String arg0) {
    byte[] seed = new byte[32];
    random.nextBytes(seed);
    try {
      FileUtil.secureDelete(new File(arg0));
    } catch (IOException e) {
      // FIXME useralert?
      // We shouldn't do this ever afaics though, with our usage of db4o...
      System.err.println("Unable to secure delete "+arg0+" for db4o, passing on to underlying adapter "+baseAdapter+" to attempt a normal deletion.");
      baseAdapter.delete(arg0);
    }
  }

  @Override
  public boolean exists(String arg0) {
    return baseAdapter.exists(arg0);
  }

  @Override
  public long getLength() throws Db4oIOException {
    return baseAdapter.getLength();
  }

  @Override
  public IoAdapter open(String arg0, boolean arg1, long arg2, boolean arg3)
      throws Db4oIOException {
    EncryptingIoAdapter adapter =
      new EncryptingIoAdapter(baseAdapter.open(arg0, arg1, arg2, arg3), key, random);
    adapter.seek(0);
    return adapter;
  }

  @Override
  public synchronized int read(byte[] buffer, int length) throws Db4oIOException {
    int readBytes;
    try {
      readBytes = baseAdapter.read(buffer, length);
    } catch (Db4oIOException e) {
      System.err.println("Unable to read: "+e);
      e.printStackTrace();
      try {
        // Position may have changed.
        baseAdapter.seek(position);
      } catch (Db4oIOException e1) {
        System.err.println("Unable to seek, closing database file: "+e1);
        e1.printStackTrace();
        // Must close because don't know position accurately now.
        close();
      }
      throw e;
    }
    if(readBytes <= 0) return readBytes;
    // CTR mode decryption
    int totalDecrypted = 0;
    int blockOffset = (int) (position % BLOCK_SIZE_BYTES);
    int blockRemaining = BLOCK_SIZE_BYTES - blockOffset;
    int toDecrypt = readBytes;
    while(toDecrypt > 0) {
      int decrypt = Math.min(toDecrypt, blockRemaining);
      long thisBlockPosition = position - blockOffset;
      if(blockPosition != thisBlockPosition) {
        // Encrypt key + position
        byte[] input = key.clone();
        byte[] counter = Fields.longToBytes(thisBlockPosition);
        for(int i=0;i<counter.length;i++)
          input[key.length - 8 + i] ^= counter[i];
        cipher.encipher(input, blockOutput);
        blockPosition = thisBlockPosition;
      }
      for(int i=0;i<decrypt;i++)
        buffer[i+totalDecrypted] ^= blockOutput[i + blockOffset];
      position += decrypt;
      totalDecrypted += decrypt;
      toDecrypt -= decrypt;
      blockOffset = 0;
      blockRemaining = BLOCK_SIZE_BYTES;
    }
    return readBytes;
  }

  @Override
  public synchronized void seek(long arg0) throws Db4oIOException {
    if(arg0 < 0) throw new IllegalArgumentException();
    baseAdapter.seek(arg0);
    position = arg0;
  }

  @Override
  public void sync() throws Db4oIOException {
    baseAdapter.sync();
  }

  @Override
  public synchronized void write(byte[] inputBuffer, int length) throws Db4oIOException {
    // Do not clobber the buffer!
    byte[] buffer = Arrays.copyOf(inputBuffer, length);
    // CTR mode encryption
    int totalDecrypted = 0;
    int blockOffset = (int) (position % BLOCK_SIZE_BYTES);
    int blockRemaining = BLOCK_SIZE_BYTES - blockOffset;
    int toDecrypt = length;
    while(toDecrypt > 0) {
      int decrypt = Math.min(toDecrypt, blockRemaining);
      long thisBlockPosition = position - blockOffset;
      if(blockPosition != thisBlockPosition) {
        // Encrypt key + position
        byte[] input = key.clone();
        byte[] counter = Fields.longToBytes(thisBlockPosition);
        for(int i=0;i<counter.length;i++)
          input[key.length - 8 + i] ^= counter[i];
        cipher.encipher(input, blockOutput);
        blockPosition = thisBlockPosition;
      }
      for(int i=0;i<decrypt;i++)
        buffer[i+totalDecrypted] ^= blockOutput[i + blockOffset];
      position += decrypt;
      totalDecrypted += decrypt;
      toDecrypt -= decrypt;
      blockOffset = 0;
      blockRemaining = BLOCK_SIZE_BYTES;
    }
    try {
      baseAdapter.write(buffer, length);
    } catch (Db4oIOException e) {
      System.err.println("Unable to write: "+e);
      e.printStackTrace();
      try {
        baseAdapter.seek(position);
      } catch (Db4oIOException e1) {
        System.err.println("Unable to seek, closing database file: "+e1);
        e1.printStackTrace();
        // Must close because don't know position accurately now.
        close();
      }
      throw e;
    }
  }

}
TOP

Related Classes of freenet.crypt.EncryptingIoAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.