java.lang.Object
net.i2p.crypto.SessionKeyManager
net.i2p.router.crypto.ratchet.RatchetSKM
- All Implemented Interfaces:
SessionTagListener
Session key manager for ratchet encryption.
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate classPeriodically cleans up stale ratchet sessions.(package private) classThe state for a crypto session to a single public key.Field Summary
FieldsModifier and TypeFieldDescriptionprivate booleanFalse once the manager has shut down.private RatchetSKM.CleanupEventThe queued cleanup event, kept for cancellation.protected final RouterContextThe router context.private final DestinationThe destination these sessions serve.private final HKDFKey derivation function for the ratchet tags.private final LongAdderInbound handshakes completed.private final ConcurrentHashMap<RatchetSessionTag, RatchetTagSet> Map allowing us to go from a SessionTag to the containing RatchetTagSet.private final LogLogger for ratchet session management.private final ConcurrentHashMap<PublicKey, RatchetSKM.OutboundSession> Map allowing us to go from the targeted PublicKey to the OutboundSession used.private final HashMap<PublicKey, List<RatchetSKM.OutboundSession>> Outbound sessions waiting for a reply, by key.private final DecayingHashSetFilter rejecting replayed messages.private final LongAdderLifetime counters for the debug page, incremented only at low-frequency events (session add/replace, inbound set completion, tag lookup miss), never per tag.private final LongAdderSessions replaced by a newer one.private final LongAdderTag mismatches seen.private final EncTypeThe encryption type these sessions use.private static final Comparator<String[]> Row order for the peer-keyed table: peer (column 0).private static final Comparator<String[]> Row order for the peer/set tables: peer (column 0), then set (column 1).(package private) static final longHow long unused inbound session tags are kept.(package private) static final longHow long a session stays pending in ms.private static final longAge after which a session created earlier is replaced when a new NS arrives.(package private) static final longLet outbound session tags sit around for this long before expiring them.private static final byte[]Shared empty array for zero-length values.Constructor Summary
ConstructorsConstructorDescriptionRatchetSKM(RouterContext context) For the router SKM only.RatchetSKM(RouterContext context, Destination dest) ECIES only.RatchetSKM(RouterContext context, Destination dest, EncType type) The session key manager is constructed and accessed through the client manager.Method Summary
Modifier and TypeMethodDescriptionprivate StringConsole translation for the debug page strings.(package private) voidackRequested(PublicKey target, int id, int n) Process an ACK request.(package private) voidaddRaw(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.private booleanaddSession(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.booleanaddTag(RatchetSessionTag tag, RatchetTagSet ts) SessionTagListener: map the tag to this tagset.private intAggressively expire inbound tag sets and outbound sessions.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.buildOutboundRows(Collection<RatchetSKM.OutboundSession> sessions, long now) One row per outbound session of {peer, established, last used, last received, sets}, sorted by peer.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.consumeNextAvailableTag(PublicKey target) Takes the next outbound session tag and key for sending a message to the target.consumeNextAvailableTag(PublicKey target, SessionKey key) Not supported for this key manager.consumeTag(SessionTag tag) Not supported for this key manager.Determines whether a session key was received for the given session tag.(package private) booleancreateSession(PublicKey target, Destination d, HandshakeState state, ReplyCallback callback) Inbound or outbound.voidcreateSession(PublicKey target, SessionKey key) Not supported for this key manager.voidexpireTag(RatchetSessionTag tag, RatchetTagSet ts) Remove the tag associated with this tagset.voidfailTags(PublicKey target, SessionKey key, TagSetHandle ts) Not supported for this key manager.intgetAvailableTags(PublicKey target, SessionKey key) Determine (approximately) how many available session tags for the current target have been confirmed and are available.longgetAvailableTimeLeft(PublicKey target, SessionKey key) Determine how long the available tags will be available for before expiring, in milliseconds.getCurrentKey(PublicKey target) Not supported for this key manager.getCurrentOrNewKey(PublicKey target) Not supported for this key manager.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}.long[]Debug overview stats as {inbound tags, outbound sessions, sessions created, sessions replaced, inbound sets completed, inbound tag misses}.The session counters line, or null when all counters are zero.The local destination for this SKM.(package private) DestinationgetDestination(PublicKey target) The far-end destination for a public key.intThe configured threshold for sending more tags.private Set<RatchetSKM.OutboundSession> OutboundSession - used only by HTML.private Set<RatchetTagSet> A snapshot of all inbound ratchet tag sets.private Map<PublicKey, Set<RatchetTagSet>> Return a map of PublicKey to a set of inbound RatchetTagSets for that key.private RatchetSKM.OutboundSessiongetSession(PublicKey target) Returns the pending session for a target key.intHow many to send, IF we need to.getType()The encryption type for this session key manager.(package private) booleanisDuplicate(PublicKey pk) Check if a public key is a duplicate.(package private) booleanisDuplicateRaw(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.(package private) static StringLabel 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) viacommSystem().renderPeerHTML().(package private) voidnextKeyReceived(PublicKey target, NextSessionKey key) Process a received next key.private StringRender 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.(package private) voidreceivedACK(PublicKey target, int id, int n) Process a received ACK.(package private) voidregisterCallback(PublicKey target, int id, int n, ReplyCallback callback) ACKS: Register a callback for an ACK.(package private) booleanregisterTimer(PublicKey target, Destination d, SimpleTimer2.TimedEvent timer) Side effect - binds this session to the supplied destination.voidrenderStatusHTML(Writer out) 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.(package private) static StringsetIdLabel(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.booleanshouldSendTags(PublicKey target, SessionKey key, int lowThreshold) Whether to send more tags, always false here.voidshutdown()Cannot be restarted.private StringsummaryText(long created, long replaced, long completed, long misses) Formats the session statistics for the log.voidtagsAcked(PublicKey target, SessionKey key, TagSetHandle ts) Not supported for this key manager.tagsDelivered(PublicKey target, SessionKey key, Set<SessionTag> sessionTags) Not supported for this key manager.voidtagsReceived(SessionKey key, Set<SessionTag> sessionTags) Not supported for this key manager.voidtagsReceived(SessionKey key, Set<SessionTag> sessionTags, long expire) Not supported for this key manager.voidtagsReceived(SessionKey key, RatchetSessionTag tag, long expire) One time session.(package private) static RatchetSKM.OutboundSessiontakePendingFor(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.private static StringFor debugging.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.(package private) booleanupdateSession(PublicKey target, HandshakeState oldState, HandshakeState state, ReplyCallback callback, SplitKeys split) Inbound or outbound.Methods inherited from class SessionKeyManager
createSession, failTags, shouldSendTagsModifier and TypeMethodDescriptioncreateSession(PublicKey target) Generate a new session key and associate it with the specified target.voidMark all of the tags delivered to the target up to this point as invalid, since the peer has failed to respond when they should have.booleanshouldSendTags(PublicKey target, SessionKey key) Determine if tags should be sent to the target.
Field Details
_log
Logger for ratchet session management._outboundSessions
Map allowing us to go from the targeted PublicKey to the OutboundSession used._pendingOutboundSessions
Outbound sessions waiting for a reply, by key._inboundTagSets
Map allowing us to go from a SessionTag to the containing RatchetTagSet._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
Sessions replaced by a newer one._inboundCompleted
Inbound handshakes completed._tagMisses
Tag mismatches seen._context
The router context._alive
private volatile boolean _aliveFalse once the manager has shut down._cleanupEvent
The queued cleanup event, kept for cancellation._hkdf
Key derivation function for the ratchet tags._replayFilter
Filter rejecting replayed messages._destination
The destination these sessions serve._type
The encryption type these sessions use.SESSION_TAG_DURATION_MS
static final long SESSION_TAG_DURATION_MSLet 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_MSHow 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_MSHow long a session stays pending in ms.- See Also:
SESSION_REPLACE_AGE
private static final long SESSION_REPLACE_AGEAge after which a session created earlier is replaced when a new NS arrives.- See Also:
ZEROLEN
private static final byte[] ZEROLENShared empty array for zero-length values.ROW_PEER_SET
Row order for the peer/set tables: peer (column 0), then set (column 1).ROW_PEER
Row order for the peer-keyed table: peer (column 0).
Constructor Details
RatchetSKM
For the router SKM only.- Parameters:
context- the router context
RatchetSKM
ECIES only.- Parameters:
context- the router contextdest- null for router's SKM only
RatchetSKM
The session key manager is constructed and accessed through the client manager.- Parameters:
context- the router contextdest- null for router's SKM onlytype- the encryption type
Method Details
shutdown
getDestination
The local destination for this SKM.- Returns:
- our destination or null for the router SKM
getType
The encryption type for this session key manager.- Returns:
- the encryption type
getRatchetTagSets
A snapshot of all inbound ratchet tag sets.- Returns:
- a new set, safe to iterate
getOutboundSessions
OutboundSession - used only by HTML.- Returns:
- a snapshot copy of the current outbound sessions, never null
getCurrentKey
Not supported for this key manager.- Overrides:
getCurrentKeyin classSessionKeyManager- 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
Not supported for this key manager.- Overrides:
getCurrentOrNewKeyin classSessionKeyManager- 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
Not supported for this key manager.- Overrides:
createSessionin classSessionKeyManager- Parameters:
target- the destination the session is established withkey- the session key to associate, whose expiry metrics start at this call- Throws:
UnsupportedOperationException- always; the ratchet key manager does not support this
isDuplicate
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 keyd- null if unknownstate- the handshake statecallback- 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 keyoldState- null for inbound, pre-clone for outboundstate- the handshake statecallback- the reply callbacksplit- 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 placeoldState- 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
Process a received next key.- Parameters:
target- the target public keykey- the next session key
registerTimer
Side effect - binds this session to the supplied destination.- Parameters:
target- the target public keyd- the far-end Destination for this PublicKey if known, or nulltimer- the timer event- Returns:
- true if registered
getDestination
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
Not supported for this key manager.- Overrides:
consumeNextAvailableTagin classSessionKeyManager- Parameters:
target- the destination the tag was sent tokey- 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
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:
getTagsToSendin classSessionKeyManager- Returns:
- the configured value (not adjusted for current available)
getLowThreshold
public int getLowThreshold()The configured threshold for sending more tags.- Overrides:
getLowThresholdin classSessionKeyManager- Returns:
- the configured value
shouldSendTags
Whether to send more tags, always false here.- Overrides:
shouldSendTagsin classSessionKeyManager- Parameters:
target- the destination whose tags are being consideredkey- the session keylowThreshold- the low threshold- Returns:
- false always
getAvailableTags
Determine (approximately) how many available session tags for the current target have been confirmed and are available.- Overrides:
getAvailableTagsin classSessionKeyManager- Parameters:
target- the destination the tags were sent tokey- the session key those tags were issued under- Returns:
- the available tags
getAvailableTimeLeft
Determine how long the available tags will be available for before expiring, in milliseconds.- Overrides:
getAvailableTimeLeftin classSessionKeyManager- Parameters:
target- the destination the tags were sent tokey- the session key those tags were issued under- Returns:
- the available time left
tagsDelivered
Not supported for this key manager.- Overrides:
tagsDeliveredin classSessionKeyManager- Parameters:
target- the destination that acknowledged the tagskey- the session key the acknowledged tags were issued undersessionTags- modifiable; NOT copied- Returns:
- the tag set handle
- Throws:
UnsupportedOperationException- always; the ratchet key manager does not support this
failTags
Not supported for this key manager.- Overrides:
failTagsin classSessionKeyManager- Parameters:
target- the destination whose tags are being consideredkey- the session keyts- the tag set handle- Throws:
UnsupportedOperationException- always; the ratchet key manager does not support this
tagsAcked
Not supported for this key manager.- Overrides:
tagsAckedin classSessionKeyManager- Parameters:
target- the destination whose tags are being consideredkey- the session keyts- the tag set handle- Throws:
UnsupportedOperationException- always; the ratchet key manager does not support this
tagsReceived
Not supported for this key manager.- Overrides:
tagsReceivedin classSessionKeyManager- Parameters:
key- the session key the tags were received forsessionTags- modifiable; NOT copied- Throws:
UnsupportedOperationException- always; the ratchet key manager does not support this
tagsReceived
Not supported for this key manager.- Overrides:
tagsReceivedin classSessionKeyManager- Parameters:
key- the session key the tags were received forsessionTags- modifiable; NOT copiedexpire- time from now- Throws:
UnsupportedOperationException- always; the ratchet key manager does not support this
tagsReceived
One time session.- Parameters:
key- the session keytag- the ratchet session tagexpire- time from now
consumeTag
Not supported for this key manager.- Overrides:
consumeTagin classSessionKeyManager- 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
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
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
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 keyisInbound- 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
SessionTagListener: map the tag to this tagset.- Specified by:
addTagin interfaceSessionTagListener- Parameters:
tag- the session tagts- the tag set- Returns:
- true if added, false if dup
expireTag
Remove the tag associated with this tagset.- Specified by:
expireTagin interfaceSessionTagListener- Parameters:
tag- the session tagts- the tag set
registerCallback
ACKS: Register a callback for an ACK.- Parameters:
target- the target public keyid- the callback IDn- the callback countcallback- the reply callback
receivedACK
Process a received ACK.- Parameters:
target- the target public keyid- the ACK IDn- the ACK count
ackRequested
Process an ACK request.- Parameters:
target- the target public keyid- the ACK IDn- the ACK count
getRatchetTagSetsByPublicKey
Return a map of PublicKey to a set of inbound RatchetTagSets for that key. Only forrenderStatusHTML(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:
getDebugStatsin classSessionKeyManager- Returns:
- the stats, or null
renderStatusHTML
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:
renderStatusHTMLin classSessionKeyManager- Parameters:
out- the writer to render to- Throws:
IOException- if an I/O error occurs
peerCell
_t
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
The session counters line, or null when all counters are zero. Only for the debug console.- Returns:
- the summary text, or null
summaryText
Formats the session statistics for the log.- Parameters:
created- sessions created since startupreplaced- sessions replaced by newer onescompleted- inbound handshakes completedmisses- 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 buildInboundRowssessions- rows from buildOutboundRowssets- rows from buildOutboundSetRows- Returns:
- the unified rows, in inbound, session, set order
keyLabel
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) viacommSystem().renderPeerHTML().- Parameters:
key- the peer's public key, may be null- Returns:
- the base64 key hash, or "null", never null
setIdLabel
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 numberdebugID- the per-set debug sequence number- Returns:
- a label like "NSR/12", never null
buildInboundRows
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 keynow- the current time in ms- Returns:
- one row per set, never null
buildOutboundRows
One row per outbound session of {peer, established, last used, last received, sets}, sorted by peer. Pure, for unit tests.- Parameters:
sessions- the outbound sessionsnow- 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 sessionsnow- the current time in ms- Returns:
- one row per live tag set, never null
toString