Class CiphertextHeader

java.lang.Object
org.cryptacular.CiphertextHeader

public class CiphertextHeader extends Object
Cleartext header prepended to ciphertext providing data required for decryption.

Data format:

     +---------+---------+---+----------+-------+------+
     | Version | KeyName | 0 | NonceLen | Nonce | HMAC |
     +---------+---------+---+----------+-------+------+
     |                                                 |
     +--- 4 ---+--- x ---+ 1 +--- 1 ----+-- y --+- 32 -+
 

Where fields are defined as follows:

  • Version - Header version format as a negative number (4-byte integer). Current version is -2.
  • KeyName - Symbolic key name encoded as UTF-8 bytes (variable length)
  • 0 - Null byte signifying the end of the symbolic key name
  • NonceLen - Nonce length in bytes (1-byte unsigned integer)
  • Nonce - Nonce bytes (variable length)
  • HMAC - HMAC-256 over preceding fields (32 bytes)

The last two fields provide support for multiple keys at the encryption provider. A common case for multiple keys is key rotation; by tagging encrypted data with a key name, an old key may be retrieved by name to decrypt outstanding data which will be subsequently re-encrypted with a new key.

  • Field Details

    • VERSION

      private static final int VERSION
      Header version format.
      See Also:
    • HMAC_SIZE

      private static final int HMAC_SIZE
      Size of HMAC algorithm output in bytes.
      See Also:
    • MAX_NONCE_LEN

      private static final int MAX_NONCE_LEN
      Maximum nonce length in bytes.
      See Also:
    • MAX_KEYNAME_LEN

      private static final int MAX_KEYNAME_LEN
      Maximum key name length in bytes.
      See Also:
    • nonce

      private final byte[] nonce
      Header nonce field value.
    • keyName

      private final String keyName
      Header key name field value.
    • length

      private final int length
      Header length in bytes.
    • keyLookup

      private final Function<String,SecretKey> keyLookup
      Function to resolve a key from a symbolic key name.
  • Constructor Details

    • CiphertextHeader

      public CiphertextHeader(byte[] nonce, String keyName)
      Creates a new instance with a nonce and named key.
      Parameters:
      nonce - Nonce bytes.
      keyName - Key name.
    • CiphertextHeader

      public CiphertextHeader(byte[] nonce, String keyName, Function<String,SecretKey> keyLookup)
      Creates a new instance with a nonce, named key and key lookup.
      Parameters:
      nonce - Nonce bytes.
      keyName - Key name.
      keyLookup - Key lookup function.
  • Method Details

    • getLength

      public int getLength()
      Gets the header length in bytes.
      Returns:
      Header length in bytes.
    • getNonce

      public byte[] getNonce()
      Gets the bytes of the nonce/IV.
      Returns:
      Nonce bytes.
    • getKeyName

      public String getKeyName()
      Gets the encryption key name stored in the header.
      Returns:
      Encryption key name.
    • encode

      public byte[] encode()
      Encodes the header into bytes.
      Returns:
      Byte representation of header.
    • encode

      public byte[] encode(SecretKey hmacKey)
      Encodes the header into bytes.
      Parameters:
      hmacKey - Key used to generate header HMAC.
      Returns:
      Byte representation of header.
    • computeLength

      protected int computeLength()
      Returns:
      Length of this header encoded as bytes.
    • decode

      public static CiphertextHeader decode(byte[] data, Function<String,SecretKey> keyLookup) throws EncodingException
      Creates a header from encrypted data containing a cleartext header prepended to the start.
      Parameters:
      data - Encrypted data with prepended header data.
      keyLookup - Function used to look up the secret key from the symbolic key name in the header.
      Returns:
      Decoded header.
      Throws:
      EncodingException - when ciphertext header cannot be decoded.
    • decode

      public static CiphertextHeader decode(InputStream input, Function<String,SecretKey> keyLookup) throws EncodingException, StreamException
      Creates a header from encrypted data containing a cleartext header prepended to the start.
      Parameters:
      input - Input stream that is positioned at the start of ciphertext header data.
      keyLookup - Function used to look up the secret key from the symbolic key name in the header.
      Returns:
      Decoded header.
      Throws:
      EncodingException - when ciphertext header cannot be decoded.
      StreamException - on stream IO errors.
    • decodeInternal

      private static <T> CiphertextHeader decodeInternal(T source, Function<String,SecretKey> keyLookup, Function<T,Integer> readIntFn, Function<T,Byte> readByteFn, BiConsumer<T,byte[]> readBytesConsumer)
      Internal header decoding routine.
      Type Parameters:
      T - Type of input source.
      Parameters:
      source - Source of header data (input stream or byte buffer).
      keyLookup - Function to look up key from symbolic key name in header.
      readIntFn - Function that produces a 4-byte integer from the input source.
      readByteFn - Function that produces a byte from the input source.
      readBytesConsumer - Function that fills a byte array from the input source.
      Returns:
      Decoded header.
    • hmac

      private static byte[] hmac(byte[] input, int offset, int length)
      Generates an HMAC-256 over the given input byte array.
      Parameters:
      input - Input bytes.
      offset - Starting position in input byte array.
      length - Number of bytes in input to consume.
      Returns:
      HMAC as byte array.
    • readInto

      private static int readInto(InputStream input, byte[] output)
      Read output.length bytes from the input stream into the output buffer.
      Parameters:
      input - Input stream.
      output - Output buffer.
      Returns:
      number of bytes read
      Throws:
      StreamException - on stream IO errors.
    • readByte

      private static byte readByte(InputStream input)
      Read a single byte from the input stream.
      Parameters:
      input - Input stream.
      Returns:
      Byte read from input stream.
    • arraysEqual

      private static boolean arraysEqual(byte[] a, int aOff, byte[] b, int bOff, int length)
      Determines if two byte array ranges are equal bytewise.
      Parameters:
      a - First array to compare.
      aOff - Offset into first array.
      b - Second array to compare.
      bOff - Offset into second array.
      length - Number of bytes to compare.
      Returns:
      True if every byte in the given range is equal, false otherwise.