Package net.i2p.router.crypto
Class TransientSessionKeyManager
java.lang.Object
net.i2p.crypto.SessionKeyManager
net.i2p.router.crypto.TransientSessionKeyManager
Implement the session key management, but keep everything in memory (don't write
to disk). However, this being java, we cannot guarantee that the keys aren't swapped
out to disk so this should not be considered secure in that sense.
The outbound and inbound sides are completely independent, each with
their own keys and tags.
For a new session, outbound tags are not considered delivered until an ack is received.
Otherwise, the loss of the first message would render all subsequent messages
undecryptable. True?
For an existing session, outbound tags are immediately considered delivered, and are
later revoked if the ack times out. This prevents massive stream slowdown caused by
repeated tag delivery after the minimum tag threshold is reached. Included tags
pushes messages above the ideal 1956 size by ~2KB and causes excessive fragmentation
and padding. As the tags are not seen by the streaming lib, they aren't accounted
for in the window size, and one or more of a series of large messages is likely to be dropped,
either due to high fragmentation or drop priorites at the tunnel OBEP.
For this to work, the minimum tag threshold and tag delivery quanitity defined in
GarlicMessageBuilder must be chosen with streaming lib windows sizes in mind.
If a single TagSet is not delivered, there will be no stall as long as the
current window size is smaller than the minimum tag threshold.
Additional TagSets will be sent before the acked tags completely run out. See below.
all subsequent messages will fail to decrypt.
See ConnectionOptions in streaming for more information.
There are large inefficiencies caused by the repeated delivery of tags in a new session.
With an initial streaming window size of 6 and 40 tags per delivery, a web server
would deliver up to 240 tags (7680 bytes, not including bundled leaseset, etc.)
in the first volley of the response.
Could the two directions be linked somehow, such that the initial request could
contain a key or tags for the response?
Should the tag threshold and quantity be adaptive?
Todo: Switch to ConcurrentHashMaps and ReadWriteLocks, only get write lock during cleanup
-
Field Summary
Modifier and TypeFieldDescriptionprotected final I2PAppContext
static final int
This was 100 since 0.6.1.10 (50 before that).static final int
dittostatic final int
a few MB? how about 24 MB! This is the max size of _inboundTagSets. -
Constructor Summary
ConstructorDescriptionTransientSessionKeyManager
(I2PAppContext context) The session key manager should only be constructed and accessed through the application context.TransientSessionKeyManager
(I2PAppContext context, int tagsToSend, int lowThreshold) -
Method Summary
Modifier and TypeMethodDescriptionconsumeNextAvailableTag
(PublicKey target, SessionKey key) Retrieve the next available session tag for identifying the use of the given key when communicating with the target.consumeTag
(SessionTag tag) Determine if we have received a session key associated with the given session tag, and if so, discard it (but keep track for frequent dups) and return the decryption key it was received with (via tagsReceived(...)).void
createSession
(PublicKey target, SessionKey key) Associate a new session key with the specified target.void
Deprecated.unused and rather drasticvoid
failTags
(PublicKey target, SessionKey key, TagSetHandle ts) Mark these tags as invalid, since the peer has failed to ack them in time.int
getAvailableTags
(PublicKey target, SessionKey key) Determine (approximately) how many available session tags for the current target have been confirmed and are availablelong
getAvailableTimeLeft
(PublicKey target, SessionKey key) Determine how long the available tags will be available for before expiring, in millisecondsgetCurrentKey
(PublicKey target) Retrieve the session key currently associated with encryption to the target, or null if a new session key should be generated.getCurrentOrNewKey
(PublicKey target) Retrieve the session key currently associated with encryption to the target.int
int
How many to send, IF we need to.void
renderStatusHTML
(Writer out) boolean
shouldSendTags
(PublicKey target, SessionKey key, int lowThreshold) void
shutdown()
Called when the system is closing down, instructing the session key manager to take whatever precautions are necessary (saving state, etc)void
tagsAcked
(PublicKey target, SessionKey key, TagSetHandle ts) Mark these tags as acked, start to use them (if we haven't already) If the set was previously failed, it will be added back in.tagsDelivered
(PublicKey target, SessionKey key, Set<SessionTag> sessionTags) Take note of the fact that the given sessionTags associated with the key for encryption to the target have been sent.void
tagsReceived
(SessionKey key, Set<SessionTag> sessionTags) Accept the given tags and associate them with the given key for decryptionvoid
tagsReceived
(SessionKey key, Set<SessionTag> sessionTags, long expire) Accept the given tags and associate them with the given key for decryptionMethods inherited from class net.i2p.crypto.SessionKeyManager
createSession, shouldSendTags
-
Field Details
-
_context
-
MAX_INBOUND_SESSION_TAGS
public static final int MAX_INBOUND_SESSION_TAGSa few MB? how about 24 MB! This is the max size of _inboundTagSets.- See Also:
-
DEFAULT_TAGS
public static final int DEFAULT_TAGSThis was 100 since 0.6.1.10 (50 before that). It's important because:- Tags are 32 bytes. So it previously added 3200 bytes to an initial message. - Too many tags adds a huge overhead to short-duration connections (like http, datagrams, etc.) - Large messages have a much higher chance of being dropped due to one of their 1KB fragments being discarded by a tunnel participant. - This reduces the effective maximum datagram size because the client doesn't know when tags will be bundled, so the tag size must be subtracted from the maximum I2NP size or transport limit.
Issues with too small a value:- When tags are sent, a reply leaseset (~1KB) is always bundled. Maybe don't need to bundle more than every minute or so rather than every time? - Does the number of tags (and the threshold of 20) limit the effective streaming lib window size? Should the threshold and the number of sent tags be variable based on the message rate?
We have to be very careful if we implement an adaptive scheme, since the key manager is per-router, not per-local-dest. Or maybe that's a bad idea, and we need to move to a per-dest manager. This needs further investigation. So a value somewhat higher than the low threshold seems appropriate. Use care when adjusting these values. See ConnectionOptions in streaming, and TransientSessionKeyManager in crypto, for more information.- Since:
- 0.9.2 moved from GarlicMessageBuilder to per-SKM config
- See Also:
-
LOW_THRESHOLD
public static final int LOW_THRESHOLDditto- See Also:
-
-
Constructor Details
-
TransientSessionKeyManager
The session key manager should only be constructed and accessed through the application context. This constructor should only be used by the appropriate application context itself. -
TransientSessionKeyManager
- Parameters:
tagsToSend
- how many to send at a time, may be lower or higher than lowThreshold. 1-128lowThreshold
- below this, send more. 1-128- Since:
- 0.9.2
-
-
Method Details
-
shutdown
public void shutdown()Description copied from class:SessionKeyManager
Called when the system is closing down, instructing the session key manager to take whatever precautions are necessary (saving state, etc)- Overrides:
shutdown
in classSessionKeyManager
-
getCurrentKey
Retrieve the session key currently associated with encryption to the target, or null if a new session key should be generated. Warning - don't generate a new session if this returns null, it's racy, use getCurrentOrNewKey()- Overrides:
getCurrentKey
in classSessionKeyManager
-
getCurrentOrNewKey
Retrieve the session key currently associated with encryption to the target. Generates a new session and session key if not previously exising.- Overrides:
getCurrentOrNewKey
in classSessionKeyManager
- Parameters:
target
- public key to which the data should be encrypted, must be ELGAMAL_2048.- Returns:
- non-null
- Throws:
IllegalArgumentException
- on bad target EncType- Since:
- 0.9
-
createSession
Associate a new session key with the specified target. Metrics to determine when to expire that key begin with this call. Racy if called after getCurrentKey() to check for a current session; use getCurrentOrNewKey() in that case.- Overrides:
createSession
in classSessionKeyManager
- Parameters:
target
- public key to which the data should be encrypted, must be ELGAMAL_2048.- Throws:
IllegalArgumentException
- on bad target EncType
-
consumeNextAvailableTag
Retrieve the next available session tag for identifying the use of the given key when communicating with the target. If this returns null, no tags are available so ElG should be used with the given key (a new sessionKey should NOT be used)- Overrides:
consumeNextAvailableTag
in classSessionKeyManager
-
getTagsToSend
public int getTagsToSend()How many to send, IF we need to.- Overrides:
getTagsToSend
in classSessionKeyManager
- Returns:
- the configured value (not adjusted for current available)
- Since:
- 0.9.2
-
getLowThreshold
public int getLowThreshold()- Overrides:
getLowThreshold
in classSessionKeyManager
- Returns:
- the configured value
- Since:
- 0.9.2
-
shouldSendTags
- Overrides:
shouldSendTags
in classSessionKeyManager
- Returns:
- true if we have less than the threshold or what we have is about to expire
- Since:
- 0.9.2
-
getAvailableTags
Determine (approximately) how many available session tags for the current target have been confirmed and are available- Overrides:
getAvailableTags
in classSessionKeyManager
-
getAvailableTimeLeft
Determine how long the available tags will be available for before expiring, in milliseconds- Overrides:
getAvailableTimeLeft
in classSessionKeyManager
-
tagsDelivered
Take note of the fact that the given sessionTags associated with the key for encryption to the target have been sent. Whether to use the tags immediately (i.e. assume they will be received) or to wait until an ack, is implementation dependent. Here, we wait for the ack if the session is new, otherwise we use right away. Will this work??? If the tags are pipelined sufficiently, it will.- Overrides:
tagsDelivered
in classSessionKeyManager
- Returns:
- the TagSetHandle. Caller MUST subsequently call failTags() or tagsAcked() with this handle.
-
failTags
Deprecated.unused and rather drasticMark 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. This call essentially lets the system recover from corrupted tag sets and crashes- Overrides:
failTags
in classSessionKeyManager
-
failTags
Mark these tags as invalid, since the peer has failed to ack them in time.- Overrides:
failTags
in classSessionKeyManager
-
tagsAcked
Mark these tags as acked, start to use them (if we haven't already) If the set was previously failed, it will be added back in.- Overrides:
tagsAcked
in classSessionKeyManager
-
tagsReceived
Accept the given tags and associate them with the given key for decryption- Overrides:
tagsReceived
in classSessionKeyManager
- Parameters:
sessionTags
- modifiable; NOT copied
-
tagsReceived
Accept the given tags and associate them with the given key for decryption- Overrides:
tagsReceived
in classSessionKeyManager
- Parameters:
sessionTags
- modifiable; NOT copied. Non-null, non-empty.expire
- time from now- Since:
- 0.9.7
-
consumeTag
Determine if we have received a session key associated with the given session tag, and if so, discard it (but keep track for frequent dups) and return the decryption key it was received with (via tagsReceived(...)). returns null if no session key matches- Overrides:
consumeTag
in classSessionKeyManager
-
renderStatusHTML
- Overrides:
renderStatusHTML
in classSessionKeyManager
- Throws:
IOException
-