securityutils
Class Seal

java.lang.Object
  extended by securityutils.Seal

public abstract class Seal
extends java.lang.Object

A class for safely storing data, even when untrustworthy entities can get access to the data.

Introduction

This class provides a simple way to securely protect data from eavesdropping and tampering. Most methods and fields are private; programmers using this class should use the public methods only. The public fields are essentially informational and not hugely relevant to the application programmer.

seal(byte[], javax.crypto.SecretKey, javax.crypto.SecretKey) provides confidentiality and integrity. To read the sealed data, a malicious user would need the encryption key. To mangle it or carefully change it (without being detected by unseal(java.lang.String, long, javax.crypto.SecretKey, javax.crypto.SecretKey)), they would need the signing key. Additionally, unseal optionally ensures freshness: it will reject data that was sealed more than expirationWindow milliseconds before.

PLEASE NOTE! This class does not, by itself, protect against replay attacks — attacks in which the attacker replays a valid sealed blob within the expiration window. You can mitigate but not completely prevent this attack by setting a very low expiration window. You can fully prevent it by putting application-specific data, such as a one-time transaction ID, in the sealed blob. Then, your business logic code can detect the replayed transaction. But Seal by itself cannot do this.

To use the class, pass your data to seal to get a sealed blob. The blob is a printable (base64-encoded) String of binary data. Then you can reconstitute the blob by passing it to unseal.

You may also want to compress the data, in case it is large and you need to fit it into a small space (like an HTTP cookie). For this purpose, we provide the convenience methods compress(byte[]) and decompress(byte[]). NOTE: You must compress before sealing, and decompress after unsealing! Encrypted data will not compress!

Applications

This class is useful when you want to take trusted state — that is, state you depend on to be correct for your application to work safely — out of a trustworthy system. For example, web applications often require many hits on the user session state table in the database, and this can be a performance bottleneck. As a result, web developers would like to put the state itself in the cookie (rather than having the cookie value be an index into the state table, as with normal JSESSIONID-type cookies). However, this is not by itself safe! The user can modify their cookie and thereby modify what the server application thinks the user's session state is. The user can also read the session state, which may contain sensitive server information. We have seen and performed this attack many times in our work.

However, this class makes that practice much safer. The encryption and integrity checking ensure that, when the server unseals the data, the user (or whatever untrustworthy entity, like another computer or a network attacker) cannot have decrypted the sealed blob. Furthermore, if they modified the blob, that modification will be detected during the unsealing process, and unseal will throw a CorruptedBlobException.

Still, keep in mind the replay attack. Make sure that replays won't hurt your application, mitigate them by setting an appropriate expiration window, and/or use one-time transaction IDs for important transactions.


Field Summary
static java.lang.String BLOCK_CIPHER
          The block cipher used to protect the confidentiality of sealed data.
static java.lang.String HMAC_ALGORITHM
          The HMAC used to protect the integrity of sealed data.
 
Constructor Summary
Seal()
           
 
Method Summary
protected static byte[] base64Decode(java.lang.String data)
           
protected static java.lang.String base64Encode(byte[] data)
           
static byte[] compress(byte[] data)
           
static byte[] decompress(byte[] data)
           
static java.lang.String seal(byte[] data, javax.crypto.SecretKey encryptionKey, javax.crypto.SecretKey signingKey)
           
static byte[] unseal(java.lang.String data, long expirationWindow, javax.crypto.SecretKey encryptionKey, javax.crypto.SecretKey signingKey)
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

BLOCK_CIPHER

public static final java.lang.String BLOCK_CIPHER
The block cipher used to protect the confidentiality of sealed data.

See Also:
Constant Field Values

HMAC_ALGORITHM

public static final java.lang.String HMAC_ALGORITHM
The HMAC used to protect the integrity of sealed data.

See Also:
Constant Field Values
Constructor Detail

Seal

public Seal()
Method Detail

compress

public static byte[] compress(byte[] data)
                       throws java.io.IOException
Parameters:
data - The data to compress.
Returns:
The compressed data.
Throws:
java.io.IOException

decompress

public static byte[] decompress(byte[] data)
                         throws java.io.IOException,
                                java.util.zip.DataFormatException
Parameters:
data - The data to decompress.
Returns:
The decompressed data.
Throws:
java.io.IOException
java.util.zip.DataFormatException

base64Encode

protected static java.lang.String base64Encode(byte[] data)
                                        throws java.io.IOException
Parameters:
data - The data to encode.
Returns:
The encoded data.
Throws:
java.io.IOException

base64Decode

protected static byte[] base64Decode(java.lang.String data)
                              throws CorruptBlobException
Parameters:
data - The base64-encoded data to decode.
Returns:
The decoded data.
Throws:
CorruptBlobException

seal

public static java.lang.String seal(byte[] data,
                                    javax.crypto.SecretKey encryptionKey,
                                    javax.crypto.SecretKey signingKey)
                             throws java.io.IOException,
                                    java.security.GeneralSecurityException
Parameters:
data - The plaintext data to encrypt, timestamp, and integrity check.
encryptionKey - The key to encrypt data.
signingKey - The key to HMAC data.
Returns:
A base64-encoded representation of the sealed data.
Throws:
java.io.IOException
java.security.GeneralSecurityException

unseal

public static byte[] unseal(java.lang.String data,
                            long expirationWindow,
                            javax.crypto.SecretKey encryptionKey,
                            javax.crypto.SecretKey signingKey)
                     throws CorruptBlobException
Parameters:
data - A sealed data blob created with seal.
expirationWindow - The validity period of data in milliseconds. If 0, data never expires.
encryptionKey - The key that was used to encrypt data.
signingKey - The key that was used to sign data.
Returns:
The decrypted data.
Throws:
CorruptBlobException - if there is anything wrong with data: integrity check failure, timestamp expired, decryption failure, or anything else.