Package freenet.store.saltedhash

Source Code of freenet.store.saltedhash.CipherManager

/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.store.saltedhash;

import java.security.MessageDigest;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;

import freenet.crypt.BlockCipher;
import freenet.crypt.PCFBMode;
import freenet.crypt.SHA256;
import freenet.crypt.UnsupportedCipherException;
import freenet.crypt.ciphers.Rijndael;
import freenet.node.MasterKeys;
import freenet.support.ByteArrayWrapper;
import freenet.support.Logger;

/**
* Cipher Manager
*
* Manage all kind of digestion and encryption in store
*
* @author sdiz
*/
public class CipherManager {
  /**
   * The actual salt. 16 bytes.
   */
  private byte[] salt;

  /**
   * The original on-disk salt, may be encrypted. 16 bytes.
   */
  private byte[] diskSalt;

  CipherManager(byte[] salt, byte[] diskSalt) {
    assert salt.length == 0x10;
    this.salt = salt;
    this.diskSalt = diskSalt;
  }

  /**
   * Get salt
   *
   * @return salt
   */
  byte[] getDiskSalt() {
    return diskSalt;
  }

  /**
   * Cache for digested keys
   */
  @SuppressWarnings("serial")
  private Map<ByteArrayWrapper, byte[]> digestRoutingKeyCache = new LinkedHashMap<ByteArrayWrapper, byte[]>() {
    @Override
    protected boolean removeEldestEntry(Map.Entry<ByteArrayWrapper, byte[]> eldest) {
      return size() > 128;
    }
  };

  /**
   * Get digested routing key
   *
   * @param plainKey
   * @return
   */
  byte[] getDigestedKey(byte[] plainKey) {
    ByteArrayWrapper key = new ByteArrayWrapper(plainKey);
    synchronized (digestRoutingKeyCache) {
      byte[] dk = digestRoutingKeyCache.get(key);
      if (dk != null)
        return dk;
    }

    MessageDigest digest = SHA256.getMessageDigest();
    try {
      digest.update(plainKey);
      digest.update(salt);

      byte[] hashedRoutingKey = digest.digest();
      assert hashedRoutingKey.length == 0x20;

      synchronized (digestRoutingKeyCache) {
        digestRoutingKeyCache.put(key, hashedRoutingKey);
      }

      return hashedRoutingKey;
    } finally {
      SHA256.returnMessageDigest(digest);
    }
  }

  /**
   * Encrypt this entry
   */
  void encrypt(SaltedHashFreenetStore.Entry entry, Random random) {
    if (entry.isEncrypted)
      return;

    entry.dataEncryptIV = new byte[16];
    random.nextBytes(entry.dataEncryptIV);

    PCFBMode cipher = makeCipher(entry.dataEncryptIV, entry.plainRoutingKey);
    cipher.blockEncipher(entry.header, 0, entry.header.length);
    cipher.blockEncipher(entry.data, 0, entry.data.length);

    entry.getDigestedRoutingKey();
    entry.isEncrypted = true;
  }

  /**
   * Verify and decrypt this entry
   *
   * @param routingKey
   * @return <code>true</code> if the <code>routeKey</code> match and the entry is decrypted.
   */
  boolean decrypt(SaltedHashFreenetStore.Entry entry, byte[] routingKey) {
    assert entry.header != null;
    assert entry.data != null;

    if (!entry.isEncrypted) {
      // Already decrypted
      if (Arrays.equals(entry.plainRoutingKey, routingKey))
        return true;
      else
        return false;
    }

    if (entry.plainRoutingKey != null) {
      // we knew the key
      if (!Arrays.equals(entry.plainRoutingKey, routingKey)) {
        return false;
      }
    } else {
      // we do not know the plain key, let's check the digest
      if (!Arrays.equals(entry.digestedRoutingKey, getDigestedKey(routingKey)))
        return false;
    }

    entry.plainRoutingKey = routingKey;

    PCFBMode cipher = makeCipher(entry.dataEncryptIV, entry.plainRoutingKey);
    cipher.blockDecipher(entry.header, 0, entry.header.length);
    cipher.blockDecipher(entry.data, 0, entry.data.length);

    entry.isEncrypted = false;

    return true;
  }

  /**
   * Create PCFBMode object for this key
   */
  PCFBMode makeCipher(byte[] iv, byte[] key) {
    byte[] iv2 = new byte[0x20]; // 256 bits

    System.arraycopy(salt, 0, iv2, 0, 0x10);
    System.arraycopy(iv, 0, iv2, 0x10, 0x10);

    try {
      BlockCipher aes = new Rijndael(256, 256);
      aes.initialize(key);

      return PCFBMode.create(aes, iv2);
    } catch (UnsupportedCipherException e) {
      Logger.error(this, "Rijndael not supported!", e);
      throw new Error("Rijndael not supported!", e);
    }
  }

  public void shutdown() {
    MasterKeys.clear(salt);
    MasterKeys.clear(diskSalt);
  }
}
TOP

Related Classes of freenet.store.saltedhash.CipherManager

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.