StoreController.java :  » Password » thinpass » com » hecticant » thinpass » persistence » Android Open Source

Android Open Source » Password » thinpass 
thinpass » com » hecticant » thinpass » persistence » StoreController.java
package com.hecticant.thinpass.persistence;

import java.util.List;

import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

/**
 * A singleton that manages the default store.
 * 
 * @author Pedro Fonseca
 */
public class StoreController {
  private static final String TAG = "StoreController";
  private static final String SKEY_KEY = "SECRETKEY";
  private static final String CHAL_KEY = "CHALLENGE";
  private static final String SSAL_KEY = "SECRETSALT";
  private static final String MSAL_KEY = "MASTERSALT";
  
  private static StoreController scSingleton;
  
  private Store store;
  
  private StoreController(Object context) {
    this.store = new DefaultStore(context);
  }
  
  public static synchronized StoreController getInstance(Object context) {
    if (scSingleton == null) {
      scSingleton = new StoreController(context);
    } else {
      ((DefaultStore) scSingleton.store).checkState();
    }
    return scSingleton;
  }
  
  @Override
  public Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException();
  }
  
  public long rowCount() {
    return store.countAccounts();
  }
  
  public List<Account> accountsInRange(long offset, long limit) {
    return store.accountsInRange(offset, limit);
  }
    
  public List<Account> accounts() {
    return ((DefaultStore) store).accounts();
  }
  
  /**
   * Adds a new account to the store. The account id for this account is 
   * automatically generated by the <code>Store</code>. 
   * <p>
   * The underlying store saves the data "as is" therefore the caller is 
   * responsible for encrypting sensitive information before passing it 
   * to this <code>StoreController</code>.
   * 
   * @param username an optional username for the account.
   * @param password a password for the account.
   * @param description a description for the account.
   * @return the new account.
   * 
   * @see Store
   * @see Account
   */
  public Account addAccount(String username, byte[] password, 
      byte[] description) 
  {
    if (password == null || description == null) {
      throw new NullPointerException();
    }
    
    long count;
    try {
      count = store.countAccounts();
      store.addAccount(username, password, description);
    } 
    catch (SQLException e) {
      return null;
    }
      
    Account a = null;
    List<Account> list = accountsInRange(count, 1);
    try {
      a = list.get(0);
    }
    catch (IndexOutOfBoundsException e) {}
    return a;
  }
  
  /** 
   * 
   * @param acc
   */
  public void updateAccount(Account acc) {
    if (acc == null) {
      throw new NullPointerException();
    }
    
    try {
      store.updateAccount(acc);
    } 
    catch (SQLException e) {}
  }
  
  public byte[] key() {
    return store.valueForKey(SKEY_KEY);
  }
  
  public byte[] passwordSalt() {
    return store.valueForKey(MSAL_KEY);
  }
  
  public void setPasswordSalt(byte[] salt) {
    store.setValueForKey(MSAL_KEY, salt, true);
  }
  
  public byte[] keySalt() {
    return store.valueForKey(SSAL_KEY);
  }
  
  public byte[] challenge() {
    return store.valueForKey(CHAL_KEY);
  }
  
  /**
   * Checks if a master key exists. The following conditions must be met: 
   * <ul>
   * <li>The salt used to generate the key must exist in the application data 
   * store
   * <li>The random key, generated when the master key is created, must be 
   * hashed in the application data store 
   * </ul>
   * 
   * @return
   * 
   * @see #storeKey(byte[], byte[], byte[])
   * @see #passwordSalt()
   * @see #challenge()
   */
  public boolean hasKey() {
    return passwordSalt() != null && challenge() != null;
  }
  
  /**
   * Saves a new key to the store. The key to be stored is a random symmetric 
   * key that is used to encrypt sensitive user data saved on the store. The 
   * key itself is protected by the master key which is derivated from a 
   * password. Thus the password can be changed without re-encrypting the 
   * store and the random key can be changed if necessary.
   * 
   * <p>
   * Master and random keys are related one-to-one. However, that can be 
   * easily extended to a one-to-many relationship.
   * 
   * @param encryptedKey a key encrypted with the master key.
   * @param salt the salt used when generating <code>check</check>
   * @param check a cryptographic checksum to verify if the 
   *       <code>encryptedKey</code> is correctly decrypted. 
   * @return if the new key was successfully stored.
   */
  public boolean storeKey(byte[] encryptedKey, byte[] salt, byte[] check) {
    if (encryptedKey == null || check == null) {
      return false;
    }
    
    SQLiteDatabase db = ((DefaultStore) store).getRawStore();
    if (!db.isOpen()) {
      return false;
    }
    
    boolean didSet = true;
    db.beginTransaction();
    try {  
      store.setValueForKey(SKEY_KEY, encryptedKey, false);
      store.setValueForKey(CHAL_KEY, check, false);
      store.setValueForKey(SSAL_KEY, salt, false); 
      db.setTransactionSuccessful();
    } 
    catch (Exception e) {
      Log.e(TAG, e.getLocalizedMessage());
      didSet = false;
    }
    finally {
      db.endTransaction();
    }
    
    return didSet;
  }
  
  /**
   * Updates the encrypted text of the key when the master key is changed.
   * The key itself must remain unchanged.
   * 
   * @param encryptedKey
   */
  public void updateKey(byte[] encryptedKey) {
    if (encryptedKey == null) {
      throw new NullPointerException();
    }
    store.setValueForKey(SKEY_KEY, encryptedKey, true);
  }
  
  /* (non-javadoc) @see #storeKey(byte[], byte[], byte[]) */
  public boolean replaceKey(byte[] encryptedKey, byte[] salt, byte[] check) {
    /* TO BE IMPLEMENTED */
    return false;
  }
  
  public void obliterateStore() {
    store.obliterate();
  }
  
  public void close() {
    store.close();
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.