Loading…

Kryptel/Java

Password Keeper Example

Creating a Password Storage Class

This example demonstrates the use of Kryptel encrypted storage for creating a secure password vault that can be used by a password manager or a similar application.

Every stored item consists of a pair of text strings – a password and a handle. The handle is used to describe the password's usage, and to represent the password where showing the password itself is not desirable. Each password record is stored in a storage object; the handle is stored in the object's attribute block, and the password is stored in the data stream. In fact, it would be better to keep both the strings in the attribute block, but our purpose here is to show how to use encrypted storage, not to create an effective implementation.

Our password storage class will also implement AutoCloseable interface. Implementing it will cost us nothing but will make the class a bit more convenient to use.

class PasswordStorage implements AutoCloseable {

Using an agent UUID is an optional but a highly recommended addition. Even if we will not convert this class to an agent later, marking a container with an unique UUID will clearly identify container's contents.

static final UUID PASSWORD_STORAGE = UUID.fromString("99C48D56-2CF1-4BCE-898D-C6738B1129FB");

Pointers to the underlying storage interfaces:

private IKryptelComponent storageComp = null;
private IEncryptedStorage storage = null;

A simple key callback that returns a single pre-defined password.

In order to reduce unrelated code as much as possible, this example uses a hard-wired password. A real-life program must never use hard-wired passwords as that makes encryption pretty useless.

private class KeyCallback implements IKeyCallback {
  private static final String PREDEFINED_PASSWORD = "qwerty";

  public KeyRecord Callback(Object arg,
                            String prompt,
                            int allowed,
                            UUID expected) throws Exception {
    KeyRecord kr = new KeyRecord();
    kr.keyMaterial = KeyIdent.IDENT_PASSWORD;
    kr.password = PREDEFINED_PASSWORD;
    return kr;
  }
}

Now it is time to add class methods. We will create three storage-related methods: CreateStorage, OpenStorage, and CloseStorage, and four password-related ones: StorePassword, GetPassword, RemovePassword, and GetAllPasswordHandles.

CreateStorage creates the password storage. We don't use compression (note CID_NULL_COMPRESSOR) as compressing several short strings is simply not worth the trouble.

void CreateStorage(String path) throws Exception {
  if (storage != null) throw new Exception("Another storage file is open");
  storageComp = Loader.CreateComponent(CID_STORAGE_7);
  storage = (IEncryptedStorage)storageComp.GetInterface(IID_IEncryptedStorage);

  try {
    storage.Create(path,
                   Loader.CreateComponent(CID_CIPHER_AES),
                   Loader.CreateComponent(CID_NULL_COMPRESSOR),
                   Loader.CreateComponent(CID_HASH_SHA256),
                   PASSWORD_STORAGE,
                   null, new KeyCallback());
  }
  catch (Exception e) {
    storageComp.DiscardComponent();
    storage = null;
    throw e;
  }
}

OpenStorage opens an existing password storage:

void OpenStorage(String path) throws Exception {
  if (storage != null) throw new Exception("Another storage file is open");

  ContainerHandlers ch = GetContainerHandlers(path);
  if (ch == null) throw new Exception("Not a valid container");
  if (ch.agent == null) throw new Exception("Not a password storage container");
  if (!ch.agent.equals(PASSWORD_STORAGE))
                    throw new Exception("Not a password storage container");

  storageComp = Loader.CreateComponent(ch.storage);
  storage = (IEncryptedStorage)storageComp.GetInterface(IID_IEncryptedStorage);

  try {
    storage.Open(path, IEncryptedStorage.CONTAINER_ACCESS_MODE.CONT_READ_WRITE,
                 null, new KeyCallback());
  }
  catch (Exception e) {
    storageComp.DiscardComponent();
    storage = null;
    throw e;
  }
}

The last container related function is CloseStorage:

void CloseStorage() throws Exception {
  if (storage != null) {
    storage.Close();
    storage = null;
    storageComp.DiscardComponent();
  }
}

The implementation of the AutoCloseable interface just calls the above function:

public void close() throws Exception {
  CloseStorage();
}

On the next step we implement four password-related functions. Note that the container's root object is used only as a holder for children objects representing passwords.

StorePassword creates a new password object, storing the password handle in the object's attribute block and the password itself in the object's data stream.

A real-life function would check if such a handle already exists and would update the password if so. In our example we simplified the code by assuming that the user would never try storing a duplicate handle.

void StorePassword(String handle, String password) throws Exception {
  if (storage == null) throw new Exception("Storage file is not open");

  IEncryptedObject root = storage.GetRootObject();
  IEncryptedObject newObj = root.CreateChildObject();

  // Store password handle
  byte[] byteSeq = handle.getBytes("UTF8");
  newObj.SetAttributeBlock(byteSeq, 0, byteSeq.length);

  // Store password
  byteSeq = password.getBytes("UTF8");
  IEncryptedStream stream = newObj.CreateStream(CT_NO_COMPRESSION);
  stream.Write(byteSeq, 0, byteSeq.length);
  stream.Close();
}

GetPassword searches the storage for the specified handle and returns the associated password, or null if the handle was not found.

String GetPassword(String handle) throws Exception {
  if (storage == null) throw new Exception("Storage file is not open");

  IEncryptedObject root = storage.GetRootObject();
  UUID[] objid = root.GetChildren();
  
  for (UUID uid: objid) {
    IEncryptedObject obj = root.GetChildObject(uid);

    // Get handle
    byte[] attr = obj.GetAttributeBlock();
    String hd = new String(attr, 0, attr.length, "UTF8");

    // If handle matches, read the password
    if (hd.equalsIgnoreCase(handle)) {
      IEncryptedStream stream = obj.OpenStream();
      byte[] pwd = new byte [(int)stream.Size()];
      stream.Read(pwd, 0, pwd.length);
      stream.Close();
      return new String(pwd, 0, pwd.length, "UTF8");
    }
  }

  return null;	// No such handle
}

RemovePassword deletes the password that has the specified handle:

void RemovePassword(String handle) throws Exception {
  if (storage == null) throw new Exception("Storage file is not open");

  IEncryptedObject root = storage.GetRootObject();
  UUID[] objid = root.GetChildren();

  for (UUID uid: objid) {
    IEncryptedObject obj = root.GetChildObject(uid);

    // Get handle
    byte[] attr = obj.GetAttributeBlock();
    String hd = new String(attr, 0, attr.length, "UTF8");

    // Handle found, delete
    if (hd.equalsIgnoreCase(handle)) {
      root.DeleteChildObject(uid);
      break;
    }
  }
}

And the last function GetAllPasswordHandles returns a string array with all the password handles in the storage.

String[] GetAllPasswordHandles() throws Exception {
  if (storage == null) throw new Exception("Storage file is not open");

  ArrayList handles = new ArrayList();

  IEncryptedObject root = storage.GetRootObject();
  UUID[] objid = root.GetChildren();

  for (UUID uid: objid) {
    IEncryptedObject obj = root.GetChildObject(uid);

    // Get handle
    byte[] attr = obj.GetAttributeBlock();
    String hd = new String(attr, 0, attr.length, "UTF8");
    handles.add(hd);
  }

  return handles.toArray(new String[handles.size()]);
}

This finalizes our simple but quite usable example. For the sake of readability we have skipped a Boolean function PasswordExists, which would make an example class a real one.

The last step is writing a test program for our brand new class:

try (PasswordStorage pwstor = new PasswordStorage()) {
  pwstor.CreateStorage("C:\\Tests\\Passwords.pws");
  pwstor.StorePassword("pwd1", "qwerty");
  pwstor.StorePassword("password2", "abc");
  pwstor.StorePassword("main password", "oops i did it again");
  pwstor.CloseStorage();

  pwstor.OpenStorage("C:\\Tests\\Passwords.pws");
  String[] handles = pwstor.GetAllPasswordHandles();
  for (String handle: handles)
    System.out.println(handle + ":\t\"" + pwstor.GetPassword(handle) + "\"");
}
catch (Exception ex) {
  System.out.println(ex.toString());
}

And running it:

pwd1:           "qwerty"
password2:      "abc"
main password:  "oops i did it again"