Encryption

KeyService

The KeyService is a service for SDK users which helps developers dealing with standard encryption and decryption problems. To facilitate this the KeyService allows to define aliases for cypher keys which can then be used to encrypt and decrypt data.

The service API focuses on the following topics:

  • Securely storing and managing passwords
  • Handling password changes via KeyChangeEvent
  • Providing encryption and decryption methods for strings and streams

The KeyService uses a master password for encrypting the secure store which will hold the passwords that have been registered with the service. By default the master password is not set and a default encryption is used. If security policies require strong encryption the master password can be provided via: environment variable, java VM parameter, servlet context initialization parameter, sertlet context attribute or via a user dialog at startup of the application.

The KeyService allows a trusted administrator to create new keys and update or delete existing keys. The administrator will be the only one who knows the keys.

The benefits of using the KeyService are:

  • The knowledge about keys is seperated from their usage thus, taking simple administrative measures, a developer can do his job without knowing the security keys (for example passwords) that are used in the solution. This increases security because less people know about password and keys that are in use.
  • Key changes can be handled in a defined and generic way. SDK developers can take measures for handling events like key created, key changed and key deleted. This further enhances security because policies which require key expiration can now easily be implemented.
  • Encrypting and decrypting data is becoming simple using the cryptographic methods provided by the KeyService. This simple access to strong encryption further enhances security since the hurdle of using cryptographic methods has been taken away from SDK developers.

Key Service API

keyservice.png Figure 1: class diagram

The KeyService provides all the functions and objects needed for handling security keys.

This service can be retrieved using:

Copy
Nm.getInstance().getKeyService()

The KeyService implements the EventSource interface which allows an SDK developer to create event listeners and register with the KeyService to be notified when key change events occur.

Creating a new alias

Copy
Nm.getInstance().getKeyService().setKey("masterPassword", "alias", "key");

After successfully creating a new alias the KeyService will fire a KeyChangeEvent. The old cipher of the KeyChangeEvent will be null.

Update / change an existing alias

Copy
Nm.getInstance().getKeyService().changeKey("masterPassword", "alias", "newkey");

After successfully updating an existing alias the KeyService will fire a KeyChangeEvent.

Delete / remove an existing alias

Copy
Nm.getInstance().getKeyService().deleteKey("masterPassword", "alias");

After successfully updating an existing alias the KeyService will fire a KeyChangeEvent. The new cipher of the KeyChangeEvent will be null.

Using ciphers

Encrypt / Decrypt a text

Copy
// create an encryptor using the key referenced by "myalias"
StringEncryptor enc=Nm.getInstance().getKeyService().getEncryptor("myalias");
// use the encryptor to encrypt a string
String encrypted=enc.encrypt(TXT);
// use the encryptor to decrypt an encrypted string
String txt=enc.decrypt(encrypted);

Encrypt / Decrypt a stream

Copy
// encrypt an output stream by wrapping it with a cipher stream
OutputStream cos = Nm.getInstance().getKeyService().encrypt("myalias", outputStream);
// use the cipher output stream
cos.write(bytes);
// flush and close when done
cos.flush();
cos.close();
Copy
// decrypt an input stream by wrapping it with a decipher stream
InputStream cis = Nm.getInstance().getKeyService().decrypt("myalias", inputStream);
// use the cipher input stream
cis.read(bytes);
// close when done
cis.close();

Handling key changes

For handling key changes we have to create an EventListener and register at the KeyService.

Then let the EventListener handle the KeyChangeEvent, cases that must be handled are:

  • key updated
  • key created
  • key deleted

The following code illustrates how a KeyChangeEvent listener might look like. Of course proper exception handling must be applied (left away for sake of readability).

Copy
import com.nm.Nm;
import com.nm.sdk.events.Event;
import com.nm.sdk.events.EventListener;
import com.nm.sdk.utils.StringUtils;
import com.nm.utils.KeyService;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import java.io.*;

public class KeyChangeEventListener implements EventListener {

    public KeyChangeEventListener() {
        Nm.getInstance().getKeyService().registerListener(this);
    }

    @Override
    public boolean handleEvent(Event event) {
        if (event instanceof KeyService.KeyChangeEvent) {
            KeyService.KeyChangeEvent kce = (KeyService.KeyChangeEvent) event;

            // only handle key changes for alias "myalias"
            if (!StringUtils.equals(kce.getAlias(), "myalias")) {
                return false;
            }

            KeyService.KeyServiceEncoderFactory oldK = kce.getOldCipher();
            KeyService.KeyServiceEncoderFactory newK = kce.getNewCipher();


            if (oldK != null && newK != null) { // key has been updated

                File source = null;
                File temp = null;
                File target = null;

                // read with old encryption
                InputStream in = oldK.getCipherInputStream(new FileInputStream(source));

                // write with new encryption
                OutputStream out = newK.getCipherOutputStream(new FileOutputStream(temp));

                // copy
                IOUtils.copy(in, out);

                // move tempfile to final destination
                FileUtils.moveFile(temp, target);
                
            } else if (oldK == null && newK != null) { // key has been created
                
                // handle key created case...
                
            } else if (oldK != null && newK == null) { // key has been deleted
                
                // handle key delete case...
                
            } else {
                
                // old and new ciphers are null, BAILOUT!
                
            }

        }
        return true;
    }
}

Application Startup & Master Password

Depending on security policies Appway provides two modes of starting the application. If no master password is defined or if the master password is given via a configuration property the application will startup going through startup phases One and Two without requiring user interaction.

If - on the other hand - a master password has been set, but it is not provided via a configuration property, the application will startup with phase One and then wait, requiring an Administrator to enter the master password in a web dialogue in order to continue with startup phase Two.

The diagram below illustrates the startup procedure:

startup.png

Figure 2: application startup

Master Password Configuration

See the dedicated Master Password for details on the configuration.