Class HandshakeState

java.lang.Object
com.southernstorm.noise.protocol.HandshakeState
All Implemented Interfaces:
Destroyable

public class HandshakeState extends Object implements Destroyable
Interface to a Noise handshake.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static int
    The handshake is complete and the data session ciphers have been split() out successfully.
    static int
    The handshake has failed due to some kind of error.
    static int
    Enumerated value that indicates that the handshake object is handling the initiator role.
    static int
    No action is required of the application yet because the handshake has not started.
    static int
    The HandshakeState expects the application to read the next message payload from the handshake.
    static int
    Enumerated value that indicates that the handshake object is handling the responder role.
    static int
    The handshake is over and the application is expected to call split() and begin data session communications.
    static int
    The HandshakeState expects the application to write the next message payload for the handshake.
  • Constructor Summary

    Constructors
    Constructor
    Description
    HandshakeState​(String protocolName, int role)
    Creates a new Noise handshake.
    HandshakeState​(String protocolName, SymmetricState state, int role)
    Creates a new Noise handshake.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    Destroys all sensitive state in the current object.
    void
    Falls back to the "XXfallback" handshake pattern.
    void
    fallback​(String patternName)
    Falls back to another handshake pattern.
    int
    Gets the next action that the application should perform for the handshake part of the protocol.
    Gets the DHState object containing a fixed local ephemeral key value for this handshake.
    Gets the DHState object containing a fixed local hybrid key value for this handshake.
    byte[]
    Gets the current value of the handshake hash.
    Gets the keypair object for the local static key.
    Gets the name of the Noise protocol.
    Gets the public key object for the remote static key.
    int
    Gets the role for this handshake.
    boolean
    Determine if this handshake has already been configured with a local static key.
    boolean
    Determine if this object has already been configured with a pre-shared key.
    boolean
    Determine if this handshake has already been configured with a remote static key.
    boolean
    Determine if this handshake requires a local static key.
    boolean
    Determine if this handshake needs a pre-shared key value and one has not been configured yet.
    boolean
    Determine if this handshake requires a remote static key.
    int
    readMessage​(byte[] message, int messageOffset, int messageLength, byte[] payload, int payloadOffset)
    Reads a message payload during the handshake.
    void
    setPreSharedKey​(byte[] key, int offset, int length)
    Sets the pre-shared key for this handshake.
    void
    setPrologue​(byte[] prologue, int offset, int length)
    Sets the prologue for this handshake.
    Splits the transport encryption CipherState objects out of this HandshakeState object once the handshake completes.
    split​(byte[] secondaryKey, int offset, int length)
    Splits the transport encryption CipherState objects out of this HandshakeObject after mixing in a secondary symmetric key.
    void
    Starts the handshake running.
    int
    writeMessage​(byte[] message, int messageOffset, byte[] payload, int payloadOffset, int payloadLength)
    Writes a message payload during the handshake.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • INITIATOR

      public static final int INITIATOR
      Enumerated value that indicates that the handshake object is handling the initiator role.
      See Also:
      Constant Field Values
    • RESPONDER

      public static final int RESPONDER
      Enumerated value that indicates that the handshake object is handling the responder role.
      See Also:
      Constant Field Values
    • NO_ACTION

      public static final int NO_ACTION
      No action is required of the application yet because the handshake has not started.
      See Also:
      Constant Field Values
    • WRITE_MESSAGE

      public static final int WRITE_MESSAGE
      The HandshakeState expects the application to write the next message payload for the handshake.
      See Also:
      Constant Field Values
    • READ_MESSAGE

      public static final int READ_MESSAGE
      The HandshakeState expects the application to read the next message payload from the handshake.
      See Also:
      Constant Field Values
    • FAILED

      public static final int FAILED
      The handshake has failed due to some kind of error.
      See Also:
      Constant Field Values
    • SPLIT

      public static final int SPLIT
      The handshake is over and the application is expected to call split() and begin data session communications.
      See Also:
      Constant Field Values
    • COMPLETE

      public static final int COMPLETE
      The handshake is complete and the data session ciphers have been split() out successfully.
      See Also:
      Constant Field Values
  • Constructor Details

    • HandshakeState

      public HandshakeState(String protocolName, SymmetricState state, int role) throws NoSuchAlgorithmException
      Creates a new Noise handshake.
      Parameters:
      protocolName - The name of the Noise protocol.
      state - The custom symmetric state
      role - The role, HandshakeState.INITIATOR or HandshakeState.RESPONDER.
      Throws:
      IllegalArgumentException - The protocolName is not formatted correctly, or the role is not recognized.
      NoSuchAlgorithmException - One of the cryptographic algorithms that is specified in the protocolName is not supported.
    • HandshakeState

      public HandshakeState(String protocolName, int role) throws NoSuchAlgorithmException
      Creates a new Noise handshake.
      Parameters:
      protocolName - The name of the Noise protocol.
      role - The role, HandshakeState.INITIATOR or HandshakeState.RESPONDER.
      Throws:
      IllegalArgumentException - The protocolName is not formatted correctly, or the role is not recognized.
      NoSuchAlgorithmException - One of the cryptographic algorithms that is specified in the protocolName is not supported.
  • Method Details

    • getProtocolName

      public String getProtocolName()
      Gets the name of the Noise protocol.
      Returns:
      The protocol name.
    • getRole

      public int getRole()
      Gets the role for this handshake.
      Returns:
      The role, HandshakeState.INITIATOR or HandshakeState.RESPONDER.
    • needsPreSharedKey

      public boolean needsPreSharedKey()
      Determine if this handshake needs a pre-shared key value and one has not been configured yet.
      Returns:
      true if a pre-shared key is needed; false if not.
    • hasPreSharedKey

      public boolean hasPreSharedKey()
      Determine if this object has already been configured with a pre-shared key.
      Returns:
      true if the pre-shared key has already been configured; false if one is not needed or it has not been configured yet.
    • setPreSharedKey

      public void setPreSharedKey(byte[] key, int offset, int length)
      Sets the pre-shared key for this handshake.
      Parameters:
      key - Buffer containing the pre-shared key value.
      offset - Offset into the buffer of the first byte of the key.
      length - The length of the pre-shared key, which must be 32.
      Throws:
      IllegalArgumentException - The length is not 32.
      UnsupportedOperationException - Pre-shared keys are not supported for this handshake type.
      IllegalStateException - The handshake has already started, so the pre-shared key can no longer be set.
    • setPrologue

      public void setPrologue(byte[] prologue, int offset, int length)
      Sets the prologue for this handshake.
      Parameters:
      prologue - Buffer containing the prologue value.
      offset - Offset into the buffer of the first byte of the prologue.
      length - The length of the prologue in bytes.
      Throws:
      IllegalStateException - The handshake has already started, so the prologue can no longer be set.
    • getLocalKeyPair

      public DHState getLocalKeyPair()
      Gets the keypair object for the local static key.
      Returns:
      The keypair, or null if a local static key is not required.
    • needsLocalKeyPair

      public boolean needsLocalKeyPair()
      Determine if this handshake requires a local static key.
      Returns:
      true if a local static key is needed; false if not.

      If the local static key has already been set, then this function will return false.

    • hasLocalKeyPair

      public boolean hasLocalKeyPair()
      Determine if this handshake has already been configured with a local static key.
      Returns:
      true if the local static key has been configured; false if not.
    • getRemotePublicKey

      public DHState getRemotePublicKey()
      Gets the public key object for the remote static key.
      Returns:
      The public key, or null if a remote static key is not required.
    • needsRemotePublicKey

      public boolean needsRemotePublicKey()
      Determine if this handshake requires a remote static key.
      Returns:
      true if a remote static key is needed; false if not.

      If the remote static key has already been set, then this function will return false.

    • hasRemotePublicKey

      public boolean hasRemotePublicKey()
      Determine if this handshake has already been configured with a remote static key.
      Returns:
      true if the remote static key has been configured; false if not.
    • getFixedEphemeralKey

      public DHState getFixedEphemeralKey()
      Gets the DHState object containing a fixed local ephemeral key value for this handshake.
      Returns:
      The fixed ephemeral key object, or null if a local ephemeral key is not required by this handshake.

      This function is intended for testing only. It can be used to establish a fixed ephemeral key for test vectors. This function should not be used in real applications.

    • getFixedHybridKey

      public DHState getFixedHybridKey()
      Gets the DHState object containing a fixed local hybrid key value for this handshake.
      Returns:
      The fixed hybrid key object, or null if a local hybrid key is not required by this handshake.

      This function is intended for testing only. It can be used to establish a fixed hybrid key for test vectors. This function should not be used in real applications.

    • start

      public void start()
      Starts the handshake running.

      This function is called after all of the handshake parameters have been provided to the HandshakeState object. This function should be followed by calls to writeMessage() or readMessage() to process the handshake messages. The getAction() function indicates the action to take next.

      Throws:
      IllegalStateException - The handshake has already started, or one or more of the required parameters has not been supplied.
      UnsupportedOperationException - An attempt was made to start a fallback handshake pattern without first calling fallback() on a previous handshake.
      See Also:
      getAction(), writeMessage(byte[], int, byte[], int, int), readMessage(byte[], int, int, byte[], int), fallback()
    • fallback

      public void fallback() throws NoSuchAlgorithmException
      Falls back to the "XXfallback" handshake pattern.

      This function is intended used to help implement the "Noise Pipes" protocol. It resets a HandshakeState object with the original handshake pattern (usually "IK"), converting it into an object with the handshake pattern "XXfallback". Information from the previous session such as the local keypair, the initiator's ephemeral key, the prologue value, and the pre-shared key, are passed to the new session.

      Once the fallback has been initiated, the application can set new values for the handshake parameters if the values from the previous session do not apply. For example, the application may use a different prologue for the fallback than for the original session.

      After setting any new parameters, the application calls start() again to restart the handshake from where it left off before the fallback.

      Note that this function reverses the roles of initiator and responder.

      Throws:
      UnsupportedOperationException - The current handshake pattern is not compatible with "XXfallback".
      IllegalStateException - The previous protocol has not started or it has not reached the fallback position yet.
      NoSuchAlgorithmException - One of the cryptographic algorithms that is specified in the new protocolName is not supported.
      See Also:
      start()
    • fallback

      public void fallback(String patternName) throws NoSuchAlgorithmException
      Falls back to another handshake pattern.
      Parameters:
      patternName - The name of the pattern to fall back to; e.g. "XXfallback", "NXfallback", etc.

      This function resets a HandshakeState object with the original handshake pattern, and converts it into an object with the new handshake patternName. Information from the previous session such as the local keypair, the initiator's ephemeral key, the prologue value, and the pre-shared key, are passed to the new session.

      Once the fallback has been initiated, the application can set new values for the handshake parameters if the values from the previous session do not apply. For example, the application may use a different prologue for the fallback than for the original session.

      After setting any new parameters, the application calls start() again to restart the handshake from where it left off before the fallback.

      The new pattern may have greater key requirements than the original; for example changing from "NK" from "XXfallback" requires that the initiator's static public key be set. The application is responsible for setting any extra keys before calling start().

      Note that this function reverses the roles of initiator and responder.

      Throws:
      UnsupportedOperationException - The current handshake pattern is not compatible with the patternName, or patternName is not a fallback pattern.
      IllegalStateException - The previous protocol has not started or it has not reached the fallback position yet.
      NoSuchAlgorithmException - One of the cryptographic algorithms that is specified in the new protocolName is not supported.
      See Also:
      start()
    • getAction

      public int getAction()
      Gets the next action that the application should perform for the handshake part of the protocol.
      Returns:
      One of HandshakeState.NO_ACTION, HandshakeState.WRITE_MESSAGE, HandshakeState.READ_MESSAGE, HandshakeState.SPLIT, or HandshakeState.FAILED.
    • writeMessage

      public int writeMessage(byte[] message, int messageOffset, byte[] payload, int payloadOffset, int payloadLength) throws ShortBufferException
      Writes a message payload during the handshake.
      Parameters:
      message - The buffer that will be populated with the handshake packet to be written to the transport.
      messageOffset - First offset within the message buffer to be populated.
      payload - Buffer containing the payload to add to the handshake message; can be null if there is no payload.
      payloadOffset - Offset into the payload buffer of the first payload buffer.
      payloadLength - Length of the payload in bytes.
      Returns:
      The length of the data written to the message buffer.
      Throws:
      IllegalStateException - The action is not WRITE_MESSAGE.
      IllegalArgumentException - The payload is null, but payloadOffset or payloadLength is non-zero.
      ShortBufferException - The message buffer does not have enough space for the handshake message.
      See Also:
      getAction(), readMessage(byte[], int, int, byte[], int)
    • readMessage

      public int readMessage(byte[] message, int messageOffset, int messageLength, byte[] payload, int payloadOffset) throws ShortBufferException, BadPaddingException
      Reads a message payload during the handshake.
      Parameters:
      message - Buffer containing the incoming handshake that was read from the transport.
      messageOffset - Offset of the first message byte.
      messageLength - The length of the incoming message.
      payload - Buffer that will be populated with the message payload.
      payloadOffset - Offset of the first byte in the payload buffer to be populated with payload data.
      Returns:
      The length of the payload.
      Throws:
      IllegalStateException - The action is not READ_MESSAGE.
      ShortBufferException - The message buffer does not have sufficient bytes for a valid message or the payload buffer does not have enough space for the decrypted payload.
      BadPaddingException - A MAC value in the message failed to verify.
      See Also:
      getAction(), writeMessage(byte[], int, byte[], int, int)
    • split

      public CipherStatePair split()
      Splits the transport encryption CipherState objects out of this HandshakeState object once the handshake completes.
      Returns:
      The pair of ciphers for sending and receiving.
      Throws:
      IllegalStateException - The action is not SPLIT.
    • split

      public CipherStatePair split(byte[] secondaryKey, int offset, int length)
      Splits the transport encryption CipherState objects out of this HandshakeObject after mixing in a secondary symmetric key.
      Parameters:
      secondaryKey - The buffer containing the secondary key.
      offset - The offset of the first secondary key byte.
      length - The length of the secondary key in bytes, which must be either 0 or 32.
      Returns:
      The pair of ciphers for sending and receiving.
      Throws:
      IllegalStateException - The action is not SPLIT.
      IllegalArgumentException - The length is not 0 or 32.
    • getHandshakeHash

      public byte[] getHandshakeHash()
      Gets the current value of the handshake hash.
      Returns:
      The handshake hash. This must not be modified by the caller.
      Throws:
      IllegalStateException - The action is not SPLIT or COMPLETE.
    • destroy

      public void destroy()
      Description copied from interface: Destroyable
      Destroys all sensitive state in the current object.
      Specified by:
      destroy in interface Destroyable