Loading…

Kryptel/Java

Handlers and Agents

Kryptel Storage

Kryptel storage (or container) has a very simple structure – it consists of objects, each of which may have a data stream and an attribute block, and may contain children objects. There always is one, and exactly one top-level (root) object.

Object's data stream and attribute block are just some raw data; the storage handler neither use nor interprets them. The difference between them is that attribute blocks are stored in the container directory; when the container is open, all the attribute blocks are memory-resident and are quickly accessible, whereas data streams get read and decrypted on request. It is up to the client to decide what to keep in attribute blocks and data streams, but quite obviously attribute blocks are better to be used for keeping small blocks of often needed data.

Kryptel storage is accessed via storage handler, which exports four storage interfaces. IEncryptedStorage and IEncryptedStorageInfo are container-related. IEncryptedObject is used for working with objects, and IEncryptedStream provides functions for reading and writing object's data stream.

The storage handler performs data encryption and decryption transparently; the client program does not need to care about that.

Because of this very generic structure, Kryptel storage may easily be used for representing any object – file, directory, thumbnail, password, and so on. The other side of this universality is some degree of inconvenience in using too generic objects. In many cases some kind of intermediary is needed.

Agents

Agent is an intermediary component that adapts generic storage to a more specialized task. The name agent may be somewhat misleading; it was used historically and stuck.

The most notable examples of agents are File Agent and Backup Agent (which are actually close relatives). They use storage objects to represent files, directories, thumbnails, and alternate streams. For instance, an object representing a file use its data stream to store the file's contents, and its attribute block contains the file's attributes – name, timestamp, etc.

File agents export specialized interfaces for working with files and directories. The agents not only map filesystem objects to generic storage objects, they also implement a number of important features like maintaining progress bars.

File agents is not the only type of agents, just the most useful one. Kryptel storage may also be used for storing non-file data records such as passwords or Yubikeys.

Agent Implementation

Techically, agent is just a component, i.e. a class that implements a public set of interfaces, that is assigned a unique Component ID, and that can be instantiated with Loader.CreateComponent.

First, define one or several interfaces, which your new agent will implement:

public interface IMyAgent {
  void DoSomething() throws MyException;
}

Define a public Component ID for your agent and Interface ID for its interface(s):

static public final UUID CID_MY_AGENT  = UUID.fromString("6D157B3F-0CCC-4616-AC89-76DAA95C928A");
static public final UUID IID_IMyAgent  = UUID.fromString("87D5F84E-B2FF-4c02-97F9-487EE2F45B1D");

If the agent implements several interfaces, it is not necessary to create IIDs for all of them. For example, Kryptel storage handlers allow access via IKryptelComponent.GetInterface to IEncryptedStorage only.

Create the class that implements your agent's interface and the mandatory interfaces IKryptelComponent and IKryptelComponent:

final class MyAgent implements IKryptelComponent, IKryptelComponent, IMyAgent {
  static final UUID componentID = CID_MY_AGENT;
  
  MyAgent(long capabilities) { ... }
  . . .
}

Add an instance creation code to com.kryptel.storage.ComponentLoader (or to your custom loader):

if (cid.equals(CID_MY_AGENT)) return new MyAgent(capabilities);

and

if ((MyAgent.componentType & mask) != 0) uidList.add(MyAgent.componentID);

That's all. In short, agent is just a standard Kryptel component without any specifics.

Agent or Class?

A storage adapter may be implemented as a class without defining new interfaces and assigning a Component ID. In many cases implementing an adapter as an agent is not really necessary.

Creating an agent is necessary when the adapter is expected to evolve. It is a common situation when several software versions co-exist – the latest version along with older ones providing compatibility with old data files. The component-based model handles this situation easily. Kryptel container keeps the Component IDs of the handler and the agent needed to handle the container; the client program calls Kryptel.GetContainerHandlers function to get the Component ID of the right agent and instantiates it. This way Kryptel's end-user programs can open containers produced by pretty ancient Kryptel versions without bothering about compatibility.