PasswordPurse
-------------
PasswordPurse is a pure java application. It manages cryptographic containers
of security credentials by protecting them under a single cleartext passphrase.
This is a very lightweight but flexible application, suited to running on
many platforms such as mobile phones and PDA's. Only one encryption
algorithm is currently supported - Bruce Schneier's Blowfish algorithm. A
subset of its implementation from the Legion of the Bouncy Castle has been
built into the application.
Starting with version 2, the project has been implemented as a hierarchy of
Maven modules. Apache maven is a double-edged sword because it makes a project
harder to understand than apache ant (used in version 1 of this project), but
it manages complex build dependencies much better. Version 2 of PasswordPurse
is complex because it has a portable core and two platform-dependent (j2se
and j2me) deployment projects. The portable core is broken into more
sub-projects to deal with the lack of compatibility in the low-level classes
of j2me and j2se (more of this later).
There is a comprehensive set of jUnit tests which exercise each important
class within each maven module that comprises the application.
Container Architecture
----------------------
A set of credentials can be associated with a particular secure service,
comprising a userid, a password and optional free-form notes. These three
fields are used to create an an instance of the Secrets class. The tuple is
separately encrypted under the current (global) passphrase to become an
instance of the EncryptedField class.
Each encrypted collection of credentials is then identified by a
case-insensitve name within an instance of the Pocket class.
A collection of Pockets is maintained by an instance of the Purse class,
which is also encrypted under the global passphrase to become an instance
of the EncryptedPurse class.
When an EncryptedPurse instance is saved to external storage, the change
from the previous version might be quite small. To conceal the scope of
changes, a cryptographically-strong random number (called "salt") is
associated with each generation of a Purse. The salt is stored inside the
EncryptedPurse, but is also stored externally (in cleartext) to be used as a
random prologue to the encryption stream.
All of these container classes (except the external salt) implement a
simple Interface called SelfDefinedField.
The structure of an externalised Purse is...
{ SALT + EncryptedPurse SelfDefinedField }
The structure of an unencrypted Purse is...
{ SALT SelfDefinedField + Version SelfDefinedField
+ PocketCount SelfDefinedField + multiple Pocket SelfDefinedFields }
The structure of a Pocket is...
{ Identifier SelfDefinedField + EncryptedField (Secrets) SelfDefinedField }
The structure of an unencrypted Secrets is...
{ Userid SelfDefinedField + Password SelfDefinedField
+ Notes SelfDefinedField }
The structure of a SelfDefinedField is...
{ inclusive length + SelfDefinedField type + UTF-8 String payload }
Security Considerations
-----------------------
1. The passphrase is not held anywhere within the externalised
EncryptedPurse byte array.
2. The external salt and SelfDefinedField header are in cleartext and
so vulnerable to simplistic editing. However, the salt is simply a
random number and so does not leak any important information.
3. The salt value is also stored within the EncryptedPurse and so it can
be used as a first-order validation once the Purse has been decrypted.
4. The EncryptedPurse SelfDefinedField header has a self-evident format.
Most tampering attempts will leave the EncryptedPurse impossible to
open successfully. Validation is intended to be comprehensive.
5. Once a purse has been opened, the individual Pockets can be searched,
renamed or deleted without needing to open the associated encrypted
Secrets.
6. When the Secrets within an individual Pocket have been decrypted, the
Secrets within all the other Pockets are still held in encrypted form.
Only one Pocket is opened (decrypted) at a time.
7. The cleartext passphrase is internalised by a CryptoManager instance.
Classes that need to manipulate EncryptedFields are passed a reference
to the relevant CryptoManager, thus minimising the number of cleartext
passphrase String instances left in the garbage collection queue.
Eventually, a finalizer will be implemented to zero out these Strings.
Manager Architecture
--------------------
Manager classes are used to collect and manipulate the more important
container classes mentioned above.
The CryptoManager class encapsulates a cleartext passphrase and an
encryption engine. It is used to validate a proposed passphrase, encrypt
or decrypt a payload and generate a salt value.
The SecretsManager class opens (decrypts), updates and closes (encrypts) a
coupled pair of Secrets and EncryptedField instances.
The PocketManager class opens, updates and closes a Pocket Identity and its
associated Secrets (via a SecretsManager).
The PurseManager class opens (decrypts), updates and closes (encrypts) a
collection of Pocket instances.
Controller Architecture
-----------------------
The Purse Controller manages the movement of an EncryptedPurse between
memory and external storage. There is a portable abstract class that has
no knowledge of the external storage implementation. The platform-dependent
concrete classes are required to manage the movement of EncryptedPurse
between external storage file systems and memory.
The PurseController supports a large set of Purse operations, such as locate,
load, open, save, close. It also supports a collection of update operations
on the individual Pockets.
User Interfaces
---------------
The user interface programs have to be platform-dependent:
The simplest is the the j2se PasswordPurseCommand class, which is a finite
state machine that interprets end-user commands and responses, and issues
appropriate prompts, status and error messages. It uses the PurseController
and various Manager classes to manipulate the Purse for the end-user.
There is also a simple gui that runs under the java ME environment. However,
j2me has many platform-dependent variants (with their own idiosyncratic
file systems) and so this first version only works on Nokia Series 60 phones.
Maven modules
-------------
The j2se and j2me modules with their user interface programs must be platform
dependent and so have to be compiled and built under the approriate toolkits.
Maven manages the dependencies within the respective toolkits (j2me is
amazingly complex!).
The portable core is compiled, built and tested under j2me. However, this isn't
as simple as first thought because the jvm's and base classes are subtly
different under j2me and j2se. To give just one example, j2se java.lang.Object
must implement java.lang.Cloneable, while j2me does not even have a
java.lang.Cloneable class!
I have used the apache Harmony class libraries and the basis for my own
portable base classes to ensure that the deployment jar built under j2se
will be loadable and executable on a j2me jvm. These Harmony classes are
packaged as a separate maven module. Similarly, I have created a portable
set of BouncyCastle classes and kept them in another maven module.
There are two more small portable modules - one is simple utility functions
and the other contains helper classes for portable jUnit tests.
Finally, the biggest portable module holds all the PasswordPurse specific
classes discussed above.
-------------------------------------