java.lang.Object
net.i2p.crypto.SessionKeyManager
net.i2p.router.crypto.ratchet.RatchetSKM
All Implemented Interfaces:
SessionTagListener

public class RatchetSKMextends SessionKeyManager implements SessionTagListener
Session key manager for ratchet encryption.
  • Field Details

    • _log

      private final Log _log
      Logger for ratchet session management.
    • _outboundSessions

      private final ConcurrentHashMap<PublicKey, RatchetSKM.OutboundSession> _outboundSessions
      Map allowing us to go from the targeted PublicKey to the OutboundSession used.
    • _pendingOutboundSessions

      private final HashMap<PublicKey, List<RatchetSKM.OutboundSession>> _pendingOutboundSessions
      Outbound sessions waiting for a reply, by key.
    • _inboundTagSets

      private final ConcurrentHashMap<RatchetSessionTag, RatchetTagSet> _inboundTagSets
      Map allowing us to go from a SessionTag to the containing RatchetTagSet.
    • _sessionsCreated

      private final LongAdder _sessionsCreated
      Lifetime counters for the debug page, incremented only at low-frequency events (session add/replace, inbound set completion, tag lookup miss), never per tag.
    • _sessionsReplaced

      private final LongAdder _sessionsReplaced
      Sessions replaced by a newer one.
    • _inboundCompleted

      private final LongAdder _inboundCompleted
      Inbound handshakes completed.
    • _tagMisses

      private final LongAdder _tagMisses
      Tag mismatches seen.
    • _context

      protected final RouterContext _context
      The router context.
    • _alive

      private volatile boolean _alive
      False once the manager has shut down.
    • _cleanupEvent

      private RatchetSKM.CleanupEvent _cleanupEvent
      The queued cleanup event, kept for cancellation.
    • _hkdf

      private final HKDF _hkdf
      Key derivation function for the ratchet tags.
    • _replayFilter

      private final DecayingHashSet _replayFilter
      Filter rejecting replayed messages.
    • _destination

      private final Destination _destination
      The destination these sessions serve.
    • _type

      private final EncType _type
      The encryption type these sessions use.
    • SESSION_TAG_DURATION_MS

      static final long SESSION_TAG_DURATION_MS
      Let outbound session tags sit around for this long before expiring them. Inbound tag expiration is set by SESSION_LIFETIME_MAX_MS.
      See Also:
    • SESSION_LIFETIME_MAX_MS

      static final long SESSION_LIFETIME_MAX_MS
      How long unused inbound session tags are kept. A few minutes longer than the outbound tag lifetime, so no reasonable network lag can cause failed decrypts.

      This is also the session idle timeout used by TransientSessionKeyManager.

      See Also:
    • SESSION_PENDING_DURATION_MS

      static final long SESSION_PENDING_DURATION_MS
      How long a session stays pending in ms.
      See Also:
    • SESSION_REPLACE_AGE

      private static final long SESSION_REPLACE_AGE
      Age after which a session created earlier is replaced when a new NS arrives.
      See Also:
    • ZEROLEN

      private static final byte[] ZEROLEN
      Shared empty array for zero-length values.
    • ROW_PEER_SET

      private static final Comparator<String[]> ROW_PEER_SET
      Row order for the peer/set tables: peer (column 0), then set (column 1).
    • ROW_PEER

      private static final Comparator<String[]> ROW_PEER
      Row order for the peer-keyed table: peer (column 0).
  • Constructor Details

    • RatchetSKM

      public RatchetSKM(RouterContext context)
      For the router SKM only.
      Parameters:
      context - the router context
    • RatchetSKM

      public RatchetSKM(RouterContext context, Destination dest)
      ECIES only.
      Parameters:
      context - the router context
      dest - null for router's SKM only
    • RatchetSKM

      public RatchetSKM(RouterContext context, Destination dest, EncType type)
      The session key manager is constructed and accessed through the client manager.
      Parameters:
      context - the router context
      dest - null for router's SKM only
      type - the encryption type
  • Method Details

    • shutdown

      public void shutdown()
      Cannot be restarted.
      Overrides:
      shutdown in class SessionKeyManager
    • getDestination

      public Destination getDestination()
      The local destination for this SKM.
      Returns:
      our destination or null for the router SKM
    • getType

      public EncType getType()
      The encryption type for this session key manager.
      Returns:
      the encryption type
    • getRatchetTagSets

      private Set<RatchetTagSet> getRatchetTagSets()
      A snapshot of all inbound ratchet tag sets.
      Returns:
      a new set, safe to iterate
    • getOutboundSessions

      private Set<RatchetSKM.OutboundSession> getOutboundSessions()
      OutboundSession - used only by HTML.
      Returns:
      a snapshot copy of the current outbound sessions, never null
    • getCurrentKey

      public SessionKey getCurrentKey(PublicKey target)
      Not supported for this key manager.
      Overrides:
      getCurrentKey in class SessionKeyManager
      Parameters:
      target - the destination whose current session key is wanted
      Returns:
      the current key
      Throws:
      UnsupportedOperationException - always; the ratchet key manager does not support this
    • getCurrentOrNewKey

      public SessionKey getCurrentOrNewKey(PublicKey target)
      Not supported for this key manager.
      Overrides:
      getCurrentOrNewKey in class SessionKeyManager
      Parameters:
      target - the destination to start or continue a session with
      Returns:
      the current or new key
      Throws:
      UnsupportedOperationException - always; the ratchet key manager does not support this
    • createSession

      public void createSession(PublicKey target, SessionKey key)
      Not supported for this key manager.
      Overrides:
      createSession in class SessionKeyManager
      Parameters:
      target - the destination the session is established with
      key - the session key to associate, whose expiry metrics start at this call
      Throws:
      UnsupportedOperationException - always; the ratchet key manager does not support this
    • isDuplicate

      boolean isDuplicate(PublicKey pk)
      Check if a public key is a duplicate.
      Parameters:
      pk - the public key to check
      Returns:
      true if a dup
    • isDuplicateRaw

      boolean isDuplicateRaw(byte[] data)
      Check whether the raw (pre-decode) bytes of a NewSession ephemeral key are a replay of a previously processed one, without adding them. Lets replays be rejected before paying for Elligator2 decoding.
      Parameters:
      data - at least 32 bytes
      Returns:
      true if a dup
    • addRaw

      void addRaw(byte[] data)
      Remember the raw (pre-decode) bytes of a successfully processed NewSession key, so a later replay of the same packet is caught by isDuplicateRaw() before any crypto work.
      Parameters:
      data - at least 32 bytes
    • createSession

      boolean createSession(PublicKey target, Destination d, HandshakeState state, ReplyCallback callback)
      Inbound or outbound. Checks state.getRole() to determine. For outbound (NS sent), adds to list of pending inbound sessions and returns true. For inbound (NS rcvd), if no other pending outbound sessions, creates one and returns true, or false if one already exists.
      Parameters:
      target - the target public key
      d - null if unknown
      state - the handshake state
      callback - null for inbound, may be null for outbound
      Returns:
      true if the session was added, false if one for this target already existed
    • updateSession

      boolean updateSession(PublicKey target, HandshakeState oldState, HandshakeState state, ReplyCallback callback, SplitKeys split)
      Inbound or outbound. Checks state.getRole() to determine. For outbound (NSR rcvd by Alice), sets session to transition to ES mode outbound. For inbound (NSR sent by Bob), sets up inbound ES tagset.
      Parameters:
      target - the target public key
      oldState - null for inbound, pre-clone for outbound
      state - the handshake state
      callback - the reply callback
      split - the split keys
      Returns:
      true if this was the first NSR received
    • takePendingFor

      static RatchetSKM.OutboundSession takePendingFor(List<RatchetSKM.OutboundSession> pending, HandshakeState oldState)
      Detach the pending session this New Session Reply belongs to, so the caller can promote it outside the map monitor. The first match wins and is removed from the list; a second entry for the same handshake is left behind for the caller to clean up as stale.
      Parameters:
      pending - the sessions queued for one target, not null, modified in place
      oldState - the pre-clone handshake state the reply carries
      Returns:
      the session to promote, or null if none matches, in which case pending is left as it was
    • nextKeyReceived

      void nextKeyReceived(PublicKey target, NextSessionKey key)
      Process a received next key.
      Parameters:
      target - the target public key
      key - the next session key
    • registerTimer

      boolean registerTimer(PublicKey target, Destination d, SimpleTimer2.TimedEvent timer)
      Side effect - binds this session to the supplied destination.
      Parameters:
      target - the target public key
      d - the far-end Destination for this PublicKey if known, or null
      timer - the timer event
      Returns:
      true if registered
    • getDestination

      Destination getDestination(PublicKey target)
      The far-end destination for a public key.
      Parameters:
      target - the target public key
      Returns:
      the far-end Destination for this PublicKey, or null
    • consumeNextAvailableTag

      public SessionTag consumeNextAvailableTag(PublicKey target, SessionKey key)
      Not supported for this key manager.
      Overrides:
      consumeNextAvailableTag in class SessionKeyManager
      Parameters:
      target - the destination the tag was sent to
      key - the session key whose use the tag identifies
      Returns:
      the next available tag, or null
      Throws:
      UnsupportedOperationException - always; the ratchet key manager does not support this
    • consumeNextAvailableTag

      public RatchetEntry consumeNextAvailableTag(PublicKey target)
      Takes the next outbound session tag and key for sending a message to the target.

      If this returns null, no session is set up yet, and a New Session message should be sent.

      If this returns non-null, the tag in the RatchetEntry will be non-null.

      If the SessionKeyAndNonce contains a HandshakeState, then the session setup is in progress, and a New Session Reply message should be sent. Otherwise, an Existing Session message should be sent.

      Parameters:
      target - the remote router to take the next outbound tag for
      Returns:
      the next available tag, or null
    • getTagsToSend

      public int getTagsToSend()
      How many to send, IF we need to.
      Overrides:
      getTagsToSend in class SessionKeyManager
      Returns:
      the configured value (not adjusted for current available)
    • getLowThreshold

      public int getLowThreshold()
      The configured threshold for sending more tags.
      Overrides:
      getLowThreshold in class SessionKeyManager
      Returns:
      the configured value
    • shouldSendTags

      public boolean shouldSendTags(PublicKey target, SessionKey key, int lowThreshold)
      Whether to send more tags, always false here.
      Overrides:
      shouldSendTags in class SessionKeyManager
      Parameters:
      target - the destination whose tags are being considered
      key - the session key
      lowThreshold - the low threshold
      Returns:
      false always
    • getAvailableTags

      public int getAvailableTags(PublicKey target, SessionKey key)
      Determine (approximately) how many available session tags for the current target have been confirmed and are available.
      Overrides:
      getAvailableTags in class SessionKeyManager
      Parameters:
      target - the destination the tags were sent to
      key - the session key those tags were issued under
      Returns:
      the available tags
    • getAvailableTimeLeft

      public long getAvailableTimeLeft(PublicKey target, SessionKey key)
      Determine how long the available tags will be available for before expiring, in milliseconds.
      Overrides:
      getAvailableTimeLeft in class SessionKeyManager
      Parameters:
      target - the destination the tags were sent to
      key - the session key those tags were issued under
      Returns:
      the available time left
    • tagsDelivered

      public TagSetHandle tagsDelivered(PublicKey target, SessionKey key, Set<SessionTag> sessionTags)
      Not supported for this key manager.
      Overrides:
      tagsDelivered in class SessionKeyManager
      Parameters:
      target - the destination that acknowledged the tags
      key - the session key the acknowledged tags were issued under
      sessionTags - modifiable; NOT copied
      Returns:
      the tag set handle
      Throws:
      UnsupportedOperationException - always; the ratchet key manager does not support this
    • failTags

      public void failTags(PublicKey target, SessionKey key, TagSetHandle ts)
      Not supported for this key manager.
      Overrides:
      failTags in class SessionKeyManager
      Parameters:
      target - the destination whose tags are being considered
      key - the session key
      ts - the tag set handle
      Throws:
      UnsupportedOperationException - always; the ratchet key manager does not support this
    • tagsAcked

      public void tagsAcked(PublicKey target, SessionKey key, TagSetHandle ts)
      Not supported for this key manager.
      Overrides:
      tagsAcked in class SessionKeyManager
      Parameters:
      target - the destination whose tags are being considered
      key - the session key
      ts - the tag set handle
      Throws:
      UnsupportedOperationException - always; the ratchet key manager does not support this
    • tagsReceived

      public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags)
      Not supported for this key manager.
      Overrides:
      tagsReceived in class SessionKeyManager
      Parameters:
      key - the session key the tags were received for
      sessionTags - modifiable; NOT copied
      Throws:
      UnsupportedOperationException - always; the ratchet key manager does not support this
    • tagsReceived

      public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags, long expire)
      Not supported for this key manager.
      Overrides:
      tagsReceived in class SessionKeyManager
      Parameters:
      key - the session key the tags were received for
      sessionTags - modifiable; NOT copied
      expire - time from now
      Throws:
      UnsupportedOperationException - always; the ratchet key manager does not support this
    • tagsReceived

      public void tagsReceived(SessionKey key, RatchetSessionTag tag, long expire)
      One time session.
      Parameters:
      key - the session key
      tag - the ratchet session tag
      expire - time from now
    • consumeTag

      public SessionKey consumeTag(SessionTag tag)
      Not supported for this key manager.
      Overrides:
      consumeTag in class SessionKeyManager
      Parameters:
      tag - the session tag whose delivered key is consumed
      Returns:
      the session key, or null
      Throws:
      UnsupportedOperationException - always; the ratchet key manager does not support this
    • consumeTag

      public SessionKeyAndNonce consumeTag(RatchetSessionTag tag)
      Determines whether a session key was received for the given session tag.

      If one was, it is discarded and returned along with the decryption key it was received with (via tagsReceived(...)). returns null if no session key matches

      If the return value has null data, it will have a non-null HandshakeState.

      Parameters:
      tag - the ratchet session tag to consume
      Returns:
      a SessionKeyAndNonce or null
    • getSession

      private RatchetSKM.OutboundSession getSession(PublicKey target)
      Returns the pending session for a target key.
      Parameters:
      target - the peer's ratchet key
      Returns:
      the session, or null if none is pending
    • addSession

      private boolean addSession(RatchetSKM.OutboundSession sess, boolean isInbound)
      For inbound, we are Bob, NS received, replace if very old For outbound, we are Alice, NSR received, never replace.
      Parameters:
      sess - the outbound session to add, keyed by its target key
      isInbound - Bob if true
      Returns:
      true if added
    • aggressiveExpire

      private int aggressiveExpire()
      Aggressively expire inbound tag sets and outbound sessions.
      Returns:
      number of tag sets expired (bogus as it overcounts inbound)
    • addTag

      public boolean addTag(RatchetSessionTag tag, RatchetTagSet ts)
      SessionTagListener: map the tag to this tagset.
      Specified by:
      addTag in interface SessionTagListener
      Parameters:
      tag - the session tag
      ts - the tag set
      Returns:
      true if added, false if dup
    • expireTag

      public void expireTag(RatchetSessionTag tag, RatchetTagSet ts)
      Remove the tag associated with this tagset.
      Specified by:
      expireTag in interface SessionTagListener
      Parameters:
      tag - the session tag
      ts - the tag set
    • registerCallback

      void registerCallback(PublicKey target, int id, int n, ReplyCallback callback)
      ACKS: Register a callback for an ACK.
      Parameters:
      target - the target public key
      id - the callback ID
      n - the callback count
      callback - the reply callback
    • receivedACK

      void receivedACK(PublicKey target, int id, int n)
      Process a received ACK.
      Parameters:
      target - the target public key
      id - the ACK ID
      n - the ACK count
    • ackRequested

      void ackRequested(PublicKey target, int id, int n)
      Process an ACK request.
      Parameters:
      target - the target public key
      id - the ACK ID
      n - the ACK count
    • getRatchetTagSetsByPublicKey

      private Map<PublicKey, Set<RatchetTagSet>> getRatchetTagSetsByPublicKey()
      Return a map of PublicKey to a set of inbound RatchetTagSets for that key. Only for renderStatusHTML(Writer) below. Does not return expired sets or sets with null keys.
      Returns:
      the ratchet tag sets by public key
    • getDebugStats

      public long[] getDebugStats()
      Debug overview stats as {inbound tags, outbound sessions, sessions created, sessions replaced, inbound sets completed, inbound tag misses}. Null for managers that do not track them. Snapshot counts only, no key material.
      Overrides:
      getDebugStats in class SessionKeyManager
      Returns:
      the stats, or null
    • renderStatusHTML

      public void renderStatusHTML(Writer out) throws IOException
      Render the session status HTML as three tables: inbound tag sets, outbound sessions, and outbound tag sets, each with a totals line, plus a line of lifetime counters.
      Overrides:
      renderStatusHTML in class SessionKeyManager
      Parameters:
      out - the writer to render to
      Throws:
      IOException - if an I/O error occurs
    • peerCell

      private String peerCell(String hashLabel)
      Render a peer cell as a router-info reference (flag, netdb link, bandwidth) when the label is a base64 hash; the label itself is the fallback for the "null" key.
      Parameters:
      hashLabel - the peer cell from a debug row
      Returns:
      the cell html
    • _t

      private String _t(String s)
      Console translation for the debug page strings.
      Parameters:
      s - the message key in the router console bundle
      Returns:
      the translated string
    • getDebugRows

      public List<String[]> getDebugRows()
      Unified debug rows for the consolidated client-SKM table: one row per inbound tag set, outbound session and outbound tag set, sharing the columns {kind, peer, set, acked, created, established, last used, last received, expires in, tags, remaining, NK sent}. Cells that do not apply to a row's kind are an em-dash. Only for the debug console.
      Returns:
      the rows, never null, empty if no sessions
    • getDebugSummary

      public String getDebugSummary()
      The session counters line, or null when all counters are zero. Only for the debug console.
      Returns:
      the summary text, or null
    • summaryText

      private String summaryText(long created, long replaced, long completed, long misses)
      Formats the session statistics for the log.
      Parameters:
      created - sessions created since startup
      replaced - sessions replaced by newer ones
      completed - inbound handshakes completed
      misses - decrypts with no matching tag
      Returns:
      the summary line
    • unifyRows

      static List<String[]> unifyRows(List<String[]> inbound, List<String[]> sessions, List<String[]> sets)
      Map the three per-kind row shapes of buildInboundRows, buildOutboundRows and buildOutboundSetRows into the shared 12-column layout, padding non-applicable cells with an em-dash. The session row's set count is dropped, as it is derivable from the set rows. Pure, for unit tests.
      Parameters:
      inbound - rows from buildInboundRows
      sessions - rows from buildOutboundRows
      sets - rows from buildOutboundSetRows
      Returns:
      the unified rows, in inbound, session, set order
    • keyLabel

      static String keyLabel(PublicKey key)
      Label a peer by the base64 hash of its public key, so the debug console can turn the cell into a router-info reference (flag, link, bandwidth) via commSystem().renderPeerHTML().
      Parameters:
      key - the peer's public key, may be null
      Returns:
      the base64 key hash, or "null", never null
    • setIdLabel

      static String setIdLabel(int id, int debugID)
      Label a tag set as its id (NSR for a new-session-request set, ES for a single established-session set) followed by its debug id.
      Parameters:
      id - the tag set id, one of the RatchetTagSet DEBUG constants or a session number
      debugID - the per-set debug sequence number
      Returns:
      a label like "NSR/12", never null
    • buildInboundRows

      static List<String[]> buildInboundRows(Map<PublicKey, Set<RatchetTagSet>> sets, long now)
      One row per inbound tag set of {peer, set, expires in, tags, remaining}, sorted by peer then set. The caller must have already dropped null-key and expired sets. Pure, for unit tests.
      Parameters:
      sets - inbound tag sets by peer key
      now - the current time in ms
      Returns:
      one row per set, never null
    • buildOutboundRows

      static List<String[]> buildOutboundRows(Collection<RatchetSKM.OutboundSession> sessions, long now)
      One row per outbound session of {peer, established, last used, last received, sets}, sorted by peer. Pure, for unit tests.
      Parameters:
      sessions - the outbound sessions
      now - the current time in ms
      Returns:
      one row per session, never null
    • buildOutboundSetRows

      static List<String[]> buildOutboundSetRows(Collection<RatchetSKM.OutboundSession> sessions, long now)
      One row per live (not yet expired) outbound tag set of {peer, set, acked, created, last used, expires in, remaining, NK sent}, sorted by peer then set. Pure, for unit tests.
      Parameters:
      sessions - the outbound sessions
      now - the current time in ms
      Returns:
      one row per live tag set, never null
    • toString

      private static String toString(PublicKey target)
      For debugging.
      Parameters:
      target - the public key to abbreviate, null renders "null"
      Returns:
      the first 20 characters of the base64 key with an ellipsis