org.hd.d.pg2k.svrCore.datasource
Class ExhibitDataTunnelSource.PacketProtector

java.lang.Object
  extended by org.hd.d.pg2k.svrCore.datasource.ExhibitDataTunnelSource.PacketProtector
Enclosing class:
ExhibitDataTunnelSource

public static final class ExhibitDataTunnelSource.PacketProtector
extends java.lang.Object

The immutable adjunct for a RawPacket that includes the HMAC and other anti-attack data. Note that this class is NOT directly serialisable, with the data fields sent in some other way, eg as HTTP header fields "out-of-band" from the actual HTTP message.


Field Summary
private static java.util.regex.Pattern fieldSplitPattern
          Field splitter regex pattern compiled once for efficiency; never null.
 int length
          The length of the entire frame/datastream being protected, input to each MAC; non-negative.
 java.util.List<ROByteArray> mac
          The immutable in-order list of MAC authenticator segments for the stream and fields herein; never null nor empty nor containing nulls.
static int MAX_CHECK_STRING_CHARS
          Maximum size in (ASCII) characters of output of toCheckString(); strictly positive.
static int MAX_SEGMENT_SIZE
          Maximum segment size; strictly positive power of two.
static int MAX_SEGMENTS
          Maximum number of segments protected stream may be broken into; strictly positive power of two.
static int MIN_SEGMENT_SIZE
          Minimum segment size (other than final segment); strictly positive power of two.
 long timestamp
          The timestamp for the RawPacket, input to each MAC; strictly positive.
 
Constructor Summary
ExhibitDataTunnelSource.PacketProtector(ExhibitDataTunnelSource.RawPacket raw, long timestamp, javax.crypto.SecretKey key)
          Create an adjunct to protect a RawPacket, including the given timestamp.
ExhibitDataTunnelSource.PacketProtector(ExhibitDataTunnelSource.RawPacket raw, javax.crypto.SecretKey key)
          Create an adjunct to protect a RawPacket, including a current timestamp.
ExhibitDataTunnelSource.PacketProtector(long timestamp, int length, java.util.List<ROByteArray> mac)
          Create an adjunct to protect a RawPacket.
 
Method Summary
static java.util.List<ROByteArray> computeMAC(long timestamp, ExhibitDataTunnelSource.RawPacket raw, javax.crypto.SecretKey key)
          Compute the MAC given the message and other fields to be included; never null.
private static int computeSegmentSize(int frameLength)
          Compute segment size; strictly positive power of two.
 boolean equals(java.lang.Object obj)
          Equality depends on all the members being equal.
static ExhibitDataTunnelSource.PacketProtector fromCheckString(java.lang.String check)
          Parses a check-string as generated by toCheckString(); never null.
 int hashCode()
          We use the timestamp and length fields in the hash for the entire collection.
 java.io.InputStream protectInputStream(java.security.Key key, java.io.InputStream is)
          Protect an input stream with our MAC; aborts with IOException in case of corruption.
 java.lang.String toCheckString()
          Generate (HTTP-header) check-string; never null nor empty.
 void validateObject()
          Checks only that the object content is valid.
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

timestamp

public final long timestamp
The timestamp for the RawPacket, input to each MAC; strictly positive.


length

public final int length
The length of the entire frame/datastream being protected, input to each MAC; non-negative.


mac

public final java.util.List<ROByteArray> mac
The immutable in-order list of MAC authenticator segments for the stream and fields herein; never null nor empty nor containing nulls. This sequence of HMAC values together makes up the message MAC. It is designed not to be possible to re-arrange these segments, as each depends in part on the value of its predecessor as well as the data in its segment.

Note that the last MAC, which depends on all the data being protected, can be used as a unique message MAC on its own.


MAX_CHECK_STRING_CHARS

public static final int MAX_CHECK_STRING_CHARS
Maximum size in (ASCII) characters of output of toCheckString(); strictly positive. Chosen to allow inclusion of the output of toCheckString() in an HTTP header.

See Also:
Constant Field Values

fieldSplitPattern

private static final java.util.regex.Pattern fieldSplitPattern
Field splitter regex pattern compiled once for efficiency; never null.


MAX_SEGMENTS

public static final int MAX_SEGMENTS
Maximum number of segments protected stream may be broken into; strictly positive power of two. This determines the maximum number of incremental portions we can process while streaming a RawPacket.

This value is capped to limit the amount of MAC data that needs to be sent, eg in an HTTP header of limited length.

See Also:
Constant Field Values

MIN_SEGMENT_SIZE

public static final int MIN_SEGMENT_SIZE
Minimum segment size (other than final segment); strictly positive power of two. This is set to be somewhat larger than the largest typical frame (ie the entire header, payload and trailer) that we usually don't want to stream, eg bulk data transfer, so that such frames/packets will get a single MAC for efficiency. This is also set large enough to amortise the cost of each segment MAC.

This is small enough to represent a reasonable incremental amount of CPU for streamed inputs.

See Also:
Constant Field Values

MAX_SEGMENT_SIZE

public static final int MAX_SEGMENT_SIZE
Maximum segment size; strictly positive power of two. This is determined from the maximum frame size and the maximum number of segments.

See Also:
Constant Field Values
Constructor Detail

ExhibitDataTunnelSource.PacketProtector

public ExhibitDataTunnelSource.PacketProtector(ExhibitDataTunnelSource.RawPacket raw,
                                               javax.crypto.SecretKey key)
                                        throws java.security.InvalidKeyException
Create an adjunct to protect a RawPacket, including a current timestamp. This must be supplied with the (secret) Key shared between the servers.

Parameters:
raw - the RawPacket to protect; never null
key - the (secret) key for the HMAC; never null
Throws:
java.security.InvalidKeyException

ExhibitDataTunnelSource.PacketProtector

public ExhibitDataTunnelSource.PacketProtector(ExhibitDataTunnelSource.RawPacket raw,
                                               long timestamp,
                                               javax.crypto.SecretKey key)
                                        throws java.security.InvalidKeyException
Create an adjunct to protect a RawPacket, including the given timestamp. This must be supplied with the (secret) Key shared between the servers.

Parameters:
raw - the RawPacket to protect; never null
timestamp - the timestamp for creation/send of the RawPacket; strictly positive
key - the (secret) key for the HMAC; never null
Throws:
java.security.InvalidKeyException

ExhibitDataTunnelSource.PacketProtector

public ExhibitDataTunnelSource.PacketProtector(long timestamp,
                                               int length,
                                               java.util.List<ROByteArray> mac)
Create an adjunct to protect a RawPacket.

Parameters:
timestamp - the timestamp for creation/send of the RawPacket; strictly positive
mac - the HMAC for the RawPacket and other fields, not checked; never null
Method Detail

toCheckString

public java.lang.String toCheckString()
Generate (HTTP-header) check-string; never null nor empty. This is a pure-ASCII single-line control-code-free check String that contains the input fields and MAC from this object to serve as the "checksum" of a RawPacket.

This object is suitable (short enough, avoidance of meta-characters) to be used directly in an HTTP header.

This value is suitable to be decoded by fromCheckString().

The format is a space-separated list of fields:

  1. The Java-style UTC timestamp in milliseconds as an unsigned decimal.
  2. The length of the protected stream in bytes as an unsigned decimal.
  3. The MAC values for each segment, in order, encoded Base64.


fromCheckString

public static ExhibitDataTunnelSource.PacketProtector fromCheckString(java.lang.String check)
Parses a check-string as generated by toCheckString(); never null. This is tolerant of some leading and trailing whitespace.

Throws:
java.lang.IllegalArgumentException - if the input is unparsable

computeSegmentSize

private static final int computeSegmentSize(int frameLength)
Compute segment size; strictly positive power of two. Given the full message/frame length (strictly positive and <= RawPacket.MAX_FRAME_SIZE) this computes the segment size between/at the MIN/MAX limits to maximise the number of segments and thus maximise the the amount of incremental MAC processing and incremental processing of streamed frames that can be done, minimising buffer working space and time/bandwidth before corruption is found.

All segments are of the same size, except the last one which may be shorter.


computeMAC

public static java.util.List<ROByteArray> computeMAC(long timestamp,
                                                     ExhibitDataTunnelSource.RawPacket raw,
                                                     javax.crypto.SecretKey key)
                                              throws java.security.InvalidKeyException
Compute the MAC given the message and other fields to be included; never null. The (secret) Key must also be supplied and be suitable for the HMAC algorithm used.

The MAC is computed on a series of segments of the input of the same length (except for a possibly-shorter final segment) producing an HMAC on each segment.

Each HMAC is computed over a binary message consisting of:

  1. the 4-byte length of the entire protected stream/frame.
  2. the 8-byte (Java-style millisecond UTC) timestamp in network order,
  3. for all segments other than the first, the HMAC of the previous segment,
  4. the full on-the-wire form of the RawPacket (including header/trailer).

The chaining should make it impossible to reorder the segments.

The segmentation is so that the data in each segment is known-safe and can be safely consumed by incremental/streaming CPU-heavy operations before subsequent segments have been received and decoded. This segmentation also means that we can abort a damaged message as soon as we check the damaged segment: we do not need to wait to receive and store and check the whole message.

Parameters:
raw - the RawPacket to protect; never null
timestamp - the timestamp for creation/send of the RawPacket; strictly positive
key - the (secret) key for the HMAC; never null
Returns:
immutable in-order list of HMACs to protect each stream segment
Throws:
java.security.InvalidKeyException - if the Key supplied is inappropriate
java.lang.IllegalArgumentException - if the timestamp is non-positive or any other argument is null
java.lang.IllegalStateException - if the HMAC algorithm is unavailable

protectInputStream

public java.io.InputStream protectInputStream(java.security.Key key,
                                              java.io.InputStream is)
Protect an input stream with our MAC; aborts with IOException in case of corruption. This acts as a transparent pass-through filter that will read a MAC-protected-segment at a time from the underlying stream and either pass it through having verified it, or abort with an IOException if the segment is corrupt.

This closes its input stream and vetoes any further operations once any error has been encountered.

We use Key rather than SecretKey, since the latter depends on Java extensions that may not be available, eg when run in JWS.

Returned input stream not to be multi-threaded.


validateObject

public void validateObject()
                    throws java.io.InvalidObjectException
Checks only that the object content is valid. This does NOT attempt to check that the MAC matches the message and fields; that must be done explicitly elsewhere.

Partly this does not check the MAC because it does not have access to the key.

Throws:
java.io.InvalidObjectException

equals

public boolean equals(java.lang.Object obj)
Equality depends on all the members being equal.

Overrides:
equals in class java.lang.Object

hashCode

public int hashCode()
We use the timestamp and length fields in the hash for the entire collection.

Overrides:
hashCode in class java.lang.Object

DHD Multimedia Gallery V1.60.69

Copyright (c) 1996-2012, Damon Hart-Davis. All rights reserved.