Package de.esoco.microsafe.model

Source Code of de.esoco.microsafe.model.MicroSafeModel

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// MicroSafe source file
// Copyright (c) 2006 Elmar Sonnenschein / esoco GmbH
// Last Change: 17.10.2006 by eso
//
// MicroSafe is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// MicroSafe is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// MicroSafe; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA   02111-1307   USA or use the contact information
// from the GNU website http://www.gnu.org
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
package de.esoco.microsafe.model;

import de.esoco.j2me.J2meLib;
import de.esoco.j2me.storage.HierarchicalStorage;
import de.esoco.j2me.storage.StorageException;
import de.esoco.j2me.util.Assert;
import de.esoco.j2me.util.ProgressMonitor;

import de.esoco.microsafe.MicroSafe;
import de.esoco.microsafe.crypto.CryptoHandler;
import de.esoco.microsafe.crypto.InvalidKeyException;

import java.io.IOException;

import org.bouncycastle.crypto.CryptoException;


/********************************************************************
* Data model class for the MicroSafe app.
*
* @author eso
*/
public class MicroSafeModel extends MicroSafeNode
{
  //~ Static fields/initializers ---------------------------------------------

  /** The major version number of the model */
  public static final int MAJOR_VERSION = 1;

  /** The minor version number of the model */
  public static final int MINOR_VERSION = 0;

  /** The number of iterations to use to generate the password verification */
  public static final int KEY_VERIFY_ITERATIONS = 10;

  //~ Instance fields --------------------------------------------------------

  /** The handler for encrypting and decrypting of nodes */
  private CryptoHandler aCryptoHandler = null;

  /** The encrypted key and value for password verification */
  private byte[] aKeyVerificationData = null;

  /**
   * If set this monitor will be notified of encryption and other long tasks
   */
  private ProgressMonitor rProgressMonitor = null;

  /** The storage to use for random access persistence */
  private HierarchicalStorage rStorage;

  //~ Constructors -----------------------------------------------------------

  /***************************************
   * Constructor that associates the node hierarchy with a particular storage.
   *
   * @param rStorage The storage to use for the model
   */
  public MicroSafeModel(HierarchicalStorage rStorage)
  {
    super(null, "MicroSafe", null);

    Assert.notFalse(rStorage.hasRandomAccess(),
            "Storage must provide random accesss");
    this.rStorage = rStorage;
  }

  //~ Methods ----------------------------------------------------------------

  /***************************************
   * To close the model and the underlying storage after saving all unsaved
   * data.
   *
   * @throws StorageException If closing the storage fails
   */
  public void close() throws StorageException
  {
    rStorage.close();
  }

  /***************************************
   * To return the cryptography handler of this model. If this has not been
   * created already the return value may be NULL. An instance will be created
   * when a key (password) is set through the method setEncryptionKey().
   *
   * @return The internal cryptography handler or NULL
   *
   * @see    #setEncryptionKey(byte[])
   */
  public CryptoHandler getCryptoHandler()
  {
    return aCryptoHandler;
  }

  /***************************************
   * Overloaded to return the current progress monitor instance used by the
   * model.
   *
   * @return The current monitor (NULL if none)
   */
  public ProgressMonitor getProgressMonitor()
  {
    return rProgressMonitor;
  }

  /***************************************
   * To return the storage where each change to the model will be stored
   * automatically.
   *
   * @return The HierarchicalStorage instance for this model
   *
   * @see    de.esoco.j2me.model.BasicHierarchyNode#getStorage()
   */
  public HierarchicalStorage getStorage()
  {
    return rStorage;
  }

  /***************************************
   * Initializes the model from the underlying storage. This method either
   * reads the node hierarchy from the storage or, if the storage is empty,
   * writes a new node record structure to the storage.
   *
   * @throws StorageException If accessing the storage fails
   * @throws IOException      If reading from or writing to the storage fails
   */
  public void initFromStorage() throws StorageException, IOException
  {
    if (rStorage.nextNode())
    {
      rStorage.reset();
      load();
    }
    else
    {
      store();
    }
  }

  /***************************************
   * Loads the node hierarchy from the underlying HierarchicalStorage
   * implementation. Invokes the method <code>readFrom()</code> from the base
   * class.
   *
   * @throws StorageException If accessing the storage fails
   * @throws IOException      If reading from the storage fails
   *
   * @see    de.esoco.j2me.model.BasicHierarchyNode#readFrom(HierarchicalStorage)
   */
  public void load() throws StorageException, IOException
  {
    initProgressMonitor(rStorage.getNodeCountEstimate(),
              MicroSafe.getString("RsLoad"));

    try
    {
      if (rStorage.nextNode())
      {
        readFrom(rStorage);
        rStorage.closeNode();
      }
    }
    finally
    {
      resetProgressMonitor();
    }
  }

  /***************************************
   * To set the cryptography key (password) for this model. If the model is
   * already encrypted and the new key differs from the previous one all
   * encrypted nodes will be decrypted and then re-encrypted with the new key.
   * If the new key is NULL encryption will be removed and all encrypted nodes
   * will be decrypted.
   *
   * <p>If a key had been associated with the model before password
   * verification data has been stored in the model. This data will be
   * compared to the new key and if it doesn't match, an InvalidKeyException
   * will be thrown.</p>
   *
   * <p>The application is responsible for setting the correct key before it
   * tries to access encrypted data.</p>
   *
   * @param  rKey The data of the new key or NULL to remove encryption
   *
   * @throws InvalidKeyException If the new key doesn't match the original one
   * @throws If                  a general cryptography error occurs
   * @throws StorageException    If updating the model data in the storage
   *                             fails
   *
   * @see    de.esoco.j2me.crypto.CryptoHandler
   */
  public void setEncryptionKey(byte[] rKey) throws InvalidKeyException,
                           CryptoException,
                           StorageException
  {
    CryptoHandler aNewCrypto = null;

    if (rKey != null)
    {
      aNewCrypto = new CryptoHandler(rKey);
      aNewCrypto.setProgressMonitor(rProgressMonitor);
    }

    if (((aNewCrypto == null) && (aCryptoHandler != null)) ||
      ((aNewCrypto != null) && !aNewCrypto.equals(aCryptoHandler)))
    {
      if ((aCryptoHandler == null) && (aKeyVerificationData != null))
      {
        verifyKey(aNewCrypto);

        return;
      }

      changeEncryption(aNewCrypto);

      // generate key verification data for the new key or reset it
      if (aNewCrypto != null)
      {
        aKeyVerificationData = aNewCrypto.generateKeyVerification(KEY_VERIFY_ITERATIONS);
      }
      else
      {
        aKeyVerificationData = null;
      }

      aCryptoHandler = aNewCrypto;
      updateStorage(rStorage);
    }
  }

  /***************************************
   * Sets the current progress monitor instance used by the model. If set this
   * monitor will be notified of encryption and other long running tasks.
   *
   * @param aMonitor The progress monitor to notify or NULL to disable
   */
  public void setProgressMonitor(ProgressMonitor aMonitor)
  {
    rProgressMonitor = aMonitor;
  }

  /***************************************
   * Stores the node hierarchy in the underlying HierarchicalStorage
   * implementation. Invokes the method <code>writeTo()</code> from the base
   * class.
   *
   * @throws StorageException If accessing the storage fails
   * @throws IOException      If writing to the storage fails
   *
   * @see    de.esoco.j2me.model.BasicHierarchyNode#writeTo(de.esoco.j2me.storage.HierarchicalStorage)
   */
  public void store() throws StorageException, IOException
  {
    initProgressMonitor(getTotalChildCount() + 1,
              MicroSafe.getString("RsStore"));

    try
    {
      rStorage.createNode();
      writeTo(rStorage);
      rStorage.closeNode();
    }
    finally
    {
      resetProgressMonitor();
    }
  }

  /***************************************
   * To check whether the model uses encryption in any of it's nodes.
   *
   * @return TRUE if encryption is used in any node of the model
   */
  public boolean usesEncryption()
  {
    // check if key verification data exists; this will even work if the
    // crypto handler (i.e., the password) hasn't been set yet
    return (aKeyVerificationData != null);
  }

  /***************************************
   * Overloaded to load additional model fields (currently a version number).
   *
   * @see de.esoco.j2me.model.BasicHierarchyNode#readFields(de.esoco.j2me.storage.HierarchicalStorage)
   */
  protected int readFields(HierarchicalStorage rStorage)
    throws StorageException, IOException
  {
    int nResult = super.readFields(rStorage);

    // Read version number
    int nMajor = rStorage.readByte();
    int nMinor = rStorage.readByte();

    // And check
    if (J2meLib.DEBUG)
    {
      Assert.notFalse((nMajor == MAJOR_VERSION) &&
              (nMinor == MINOR_VERSION),
              "Wrong model version number (" + MAJOR_VERSION +
              "." + MINOR_VERSION + " expected): " + nMajor +
              "." + nMinor);
    }

    if (rStorage.readByte() == 1)
    {
      aKeyVerificationData = rStorage.readData();
    }

    return nResult;
  }

  /***************************************
   * Overloaded to write additional model fields: the model version number and
   * the encryption data.
   *
   * @see de.esoco.j2me.model.BasicHierarchyNode#writeFields(HierarchicalStorage)
   */
  protected void writeFields(HierarchicalStorage rStorage)
    throws StorageException, IOException
  {
    boolean bEncryptionUsed = (aCryptoHandler != null);

    super.writeFields(rStorage);

    // Version 1.0
    rStorage.writeByte((byte) MAJOR_VERSION);
    rStorage.writeByte((byte) MINOR_VERSION);

    rStorage.writeByte((byte) (bEncryptionUsed ? 1 : 0));

    if (bEncryptionUsed)
    {
      rStorage.writeData(aKeyVerificationData);
    }
  }

  /***************************************
   * Verifies a new key that is already stored in a CryptoHandler instance.
   * This is done by comparing the key with the key verification data stored
   * in the model which therefore must exist already.
   *
   * @param  rNewCrypto The CryptoHander containing the new key
   *
   * @throws CryptoException     If performing the key verification fails
   * @throws InvalidKeyException If the key doesn't match the verification
   *                             data
   */
  private void verifyKey(CryptoHandler rNewCrypto) throws CryptoException,
                              InvalidKeyException
  {
    // Will throw an Exception if the verification fails
    rNewCrypto.verifyKey(aKeyVerificationData);
    aCryptoHandler = rNewCrypto;
  }
}
TOP

Related Classes of de.esoco.microsafe.model.MicroSafeModel

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.