Two formats were supported as of 0.9.48, three as of 0.9.51.
None of the readXXX() calls are cached. For efficiency, they should only be called once.
Original ElGamal format:
Holds the unencrypted 222-byte tunnel request record, with a constructor for ElGamal decryption and a method for ElGamal encryption. Iterative AES encryption/decryption is done elsewhere.
Cleartext:
bytes 0-3: tunnel ID to receive messages as bytes 4-35: local router identity hash (Unused and no accessor here) bytes 36-39: next tunnel ID bytes 40-71: next router identity hash bytes 72-103: AES-256 tunnel layer key bytes 104-135: AES-256 tunnel IV key bytes 136-167: AES-256 reply key bytes 168-183: reply IV byte 184: flags bytes 185-188: request time (in hours since the epoch) bytes 189-192: next message ID bytes 193-221: uninterpreted / random padding
Encrypted:
bytes 0-15: First 16 bytes of router hash bytes 16-527: ElGamal encrypted block (discarding zero bytes at elg[0] and elg[257])
ECIES long record format, ref: proposal 152:
Holds the unencrypted 464-byte tunnel request record, with a constructor for ECIES decryption and a method for ECIES encryption. Iterative AES encryption/decryption is done elsewhere.
Cleartext:
bytes 0-3: tunnel ID to receive messages as, nonzero bytes 4-7: next tunnel ID, nonzero bytes 8-39: next router identity hash bytes 40-71: AES-256 tunnel layer key bytes 72-103: AES-256 tunnel IV key bytes 104-135: AES-256 reply key bytes 136-151: AES-256 reply IV byte 152: flags bytes 153-155: more flags, unused, set to 0 for compatibility bytes 156-159: request time (in minutes since the epoch, rounded down) bytes 160-163: request expiration (in seconds since creation) bytes 164-167: next message ID bytes 168-x: tunnel build options (Mapping) bytes x-x: other data as implied by flags or options bytes x-463: random padding
Encrypted:
bytes 0-15: Hop's truncated identity hash bytes 16-47: Sender's ephemeral X25519 public key bytes 48-511: ChaCha20 encrypted BuildRequestRecord bytes 512-527: Poly1305 MAC
ECIES short record format, ref: proposal 157:
Holds the unencrypted 154-byte tunnel request record, with a constructor for ECIES decryption and a method for ECIES encryption. Iterative AES encryption/decryption is done elsewhere.
Cleartext:
bytes 0-3: tunnel ID to receive messages as, nonzero bytes 4-7: next tunnel ID, nonzero bytes 8-39: next router identity hash byte 40: flags bytes 41-42: more flags, unused, set to 0 for compatibility byte 43: layer enc. type bytes 44-47: request time (in minutes since the epoch, rounded down) bytes 48-51: request expiration (in seconds since creation) bytes 52-55: next message ID bytes 56-x: tunnel build options (Mapping) bytes x-x: other data as implied by flags or options bytes x-153: random padding
Encrypted:
bytes 0-15: Hop's truncated identity hash bytes 16-47: Sender's ephemeral X25519 public key bytes 48-201: ChaCha20 encrypted BuildRequestRecord bytes 202-217: Poly1305 MAC
Field Summary
Modifier and TypeFieldDescriptionprivate byte[]ChaCha reply AD for ECIES.private SessionKeyChaCha reply key for ECIES.private final byte[]The raw record data.private MessageWrapper.OneTimeSessionDerived garlic keys for short OBEP records.private SessionKeyDerived IV key for short records.private SessionKeyDerived layer key for short records.private final booleanTrue if ECIES format, false if ElGamal.private static final intDefault life of the record - 10 minutes, stored in seconds.private static final intLength of an X25519 public key, in bytes.private static final intIf set in the flag byte, this is an outbound tunnel endpoint, which means that there is no 'next hop' and that the next hop fields contain the tunnel to which the reply message should be sent.private static final intIf set in the flag byte, any peer may send a message into this tunnel, but if not set, only the current predecessor may send messages in.private static final StringHKDF info string for reply key derivation.private static final StringHKDF info string for layer key derivation.private static final StringHKDF info string for IV key derivation.private static final StringHKDF info string for garlic key and tag derivation.static final intIV size in bytes.private static final intRecord length for ElGamal format (222 bytes).private static final intRecord length for ECIES long format (464 bytes).private static final intRecord length for ECIES short format (154 bytes).private static final intMaximum options length for ECIES long format.private static final intMaximum options length for ECIES short format.private static final byte[]An all-zero key, for records that carry none.private static final intOffset for expiration in ECIES long format.private static final intOffset for expiration in ECIES short format.private static final intOffset for flags in ElGamal format.private static final intOffset for flags in ECIES long format.private static final intOffset for flags in ECIES short format.private static final intOffset for IV key in ElGamal format.private static final intOffset for IV key in ECIES long format.private static final intOffset for layer encryption type in ECIES short format.private static final intOffset for layer key in ElGamal format.private static final intOffset for layer key in ECIES long format.private static final intOffset for options in ECIES long format.private static final intOffset for options in ECIES short format.private static final intOffset for local identity hash in ElGamal format.private static final intOffset for receive tunnel in ElGamal format.private static final intOffset for reply IV in ElGamal format.private static final intOffset for reply IV in ECIES long format.static final intOffset for reply key in ElGamal format.static final intOffset for reply key in ECIES long format.private static final intOffset for request time in ElGamal format.private static final intOffset for request time in ECIES long format.private static final intOffset for request time in ECIES short format.private static final intOffset for send identity hash in ElGamal format.private static final intOffset for send identity hash in ECIES long format.private static final intOffset for send message ID in ElGamal format.private static final intOffset for send message ID in ECIES long format.private static final intOffset for send message ID in ECIES short format.private static final intOffset for send tunnel in ElGamal format.private static final intOffset for send tunnel in ECIES long format.private static final intPadding size for ElGamal format.static final intWe show 16 bytes of the peer hash outside the elGamal block.private static final booleanTest mode flag.private static KeyFactoryTest key factory.private static final byte[]Empty byte array for short record HKDF.Constructor Summary
ConstructorsConstructorDescriptionBuildRequestRecord(I2PAppContext ctx, long receiveTunnelId, long nextTunnelId, Hash nextHop, long nextMsgId, boolean isInGateway, boolean isOutEndpoint, Properties options) Creates a new ECIES short build request record.BuildRequestRecord(I2PAppContext ctx, long receiveTunnelId, long nextTunnelId, Hash nextHop, long nextMsgId, SessionKey layerKey, SessionKey ivKey, SessionKey replyKey, byte[] iv, boolean isInGateway, boolean isOutEndpoint, Properties options) Creates a new ECIES long build request record.BuildRequestRecord(I2PAppContext ctx, long receiveTunnelId, Hash peer, long nextTunnelId, Hash nextHop, long nextMsgId, SessionKey layerKey, SessionKey ivKey, SessionKey replyKey, byte[] iv, boolean isInGateway, boolean isOutEndpoint) Creates a new ElGamal build request record.BuildRequestRecord(RouterContext ctx, PrivateKey ourKey, EncryptedBuildRecord encryptedRecord) Decrypts an encrypted build request record.Method Summary
Modifier and TypeMethodDescriptionencryptECIESRecord(RouterContext ctx, PublicKey toKey, Hash toPeer) Encrypts the record using ECIES.encryptRecord(I2PAppContext ctx, PublicKey toKey, Hash toPeer) Encrypts the record using ElGamal.byte[]Returns the ChaCha reply AD (Associated Data).Returns the ChaCha reply key.byte[]getData()Returns the raw record data.longReads the expiration time.Reads the garlic keys for OBEP.booleanReads whether this hop is an inbound gateway.booleanReads whether this hop is an outbound endpoint.Reads the tunnel IV encryption key.intReads the layer encryption type.Reads the tunnel layer encryption key.Reads the next hop's identity hash.longReads the next hop's tunnel ID.Reads the tunnel build options.longReads the tunnel ID this hop should receive messages on.byte[]Reads the reply IV.Reads the reply encryption key.longReads the reply message ID.longReads the request time.(package private) static Stringrole(boolean inboundGateway, boolean outboundEndpoint) The hop's role in the tunnel, in the plain words the logs use instead of the IBGW / OBEP shorthands.Key material for DEBUG-level build interop debugging only.toString()Concise summary for log output: crypto type, hop role and tunnel IDs.
Field Details
_data
private final byte[] _dataThe raw record data._isEC
private final boolean _isECTrue if ECIES format, false if ElGamal._chachaReplyKey
ChaCha reply key for ECIES._chachaReplyAD
private byte[] _chachaReplyADChaCha reply AD for ECIES._derivedLayerKey
Derived layer key for short records._derivedIVKey
Derived IV key for short records._derivedGarlicKeys
Derived garlic keys for short OBEP records.FLAG_UNRESTRICTED_PREV
private static final int FLAG_UNRESTRICTED_PREVIf set in the flag byte, any peer may send a message into this tunnel, but if not set, only the current predecessor may send messages in. This is only set on an inbound tunnel gateway.- See Also:
FLAG_OUTBOUND_ENDPOINT
private static final int FLAG_OUTBOUND_ENDPOINTIf set in the flag byte, this is an outbound tunnel endpoint, which means that there is no 'next hop' and that the next hop fields contain the tunnel to which the reply message should be sent.- See Also:
IV_SIZE
PEER_SIZE
public static final int PEER_SIZEWe show 16 bytes of the peer hash outside the elGamal block.- See Also:
DEFAULT_EXPIRATION_SECONDS
private static final int DEFAULT_EXPIRATION_SECONDSDefault life of the record - 10 minutes, stored in seconds.- See Also:
EC_LEN
private static final int EC_LENLength of an X25519 public key, in bytes.NULL_KEY
private static final byte[] NULL_KEYAn all-zero key, for records that carry none.OFF_RECV_TUNNEL
private static final int OFF_RECV_TUNNELOffset for receive tunnel in ElGamal format.- See Also:
OFF_OUR_IDENT
private static final int OFF_OUR_IDENTOffset for local identity hash in ElGamal format.- See Also:
OFF_SEND_TUNNEL
private static final int OFF_SEND_TUNNELOffset for send tunnel in ElGamal format.- See Also:
OFF_SEND_IDENT
private static final int OFF_SEND_IDENTOffset for send identity hash in ElGamal format.- See Also:
OFF_LAYER_KEY
private static final int OFF_LAYER_KEYOffset for layer key in ElGamal format.- See Also:
OFF_IV_KEY
private static final int OFF_IV_KEYOffset for IV key in ElGamal format.- See Also:
OFF_REPLY_KEY
public static final int OFF_REPLY_KEYOffset for reply key in ElGamal format.- See Also:
OFF_REPLY_IV
private static final int OFF_REPLY_IVOffset for reply IV in ElGamal format.- See Also:
OFF_FLAG
OFF_REQ_TIME
private static final int OFF_REQ_TIMEOffset for request time in ElGamal format.- See Also:
OFF_SEND_MSG_ID
private static final int OFF_SEND_MSG_IDOffset for send message ID in ElGamal format.- See Also:
PADDING_SIZE
LENGTH
private static final int LENGTHRecord length for ElGamal format (222 bytes).- See Also:
OFF_SEND_TUNNEL_EC
private static final int OFF_SEND_TUNNEL_ECOffset for send tunnel in ECIES long format.- See Also:
OFF_SEND_IDENT_EC
private static final int OFF_SEND_IDENT_ECOffset for send identity hash in ECIES long format.- See Also:
OFF_LAYER_KEY_EC
private static final int OFF_LAYER_KEY_ECOffset for layer key in ECIES long format.- See Also:
OFF_IV_KEY_EC
private static final int OFF_IV_KEY_ECOffset for IV key in ECIES long format.- See Also:
OFF_REPLY_KEY_EC
public static final int OFF_REPLY_KEY_ECOffset for reply key in ECIES long format.- See Also:
OFF_REPLY_IV_EC
private static final int OFF_REPLY_IV_ECOffset for reply IV in ECIES long format.- See Also:
OFF_FLAG_EC
private static final int OFF_FLAG_ECOffset for flags in ECIES long format.- See Also:
OFF_REQ_TIME_EC
private static final int OFF_REQ_TIME_ECOffset for request time in ECIES long format.- See Also:
OFF_EXPIRATION
private static final int OFF_EXPIRATIONOffset for expiration in ECIES long format.- See Also:
OFF_SEND_MSG_ID_EC
private static final int OFF_SEND_MSG_ID_ECOffset for send message ID in ECIES long format.- See Also:
OFF_OPTIONS
private static final int OFF_OPTIONSOffset for options in ECIES long format.- See Also:
LENGTH_EC
private static final int LENGTH_ECRecord length for ECIES long format (464 bytes).- See Also:
MAX_OPTIONS_LENGTH
private static final int MAX_OPTIONS_LENGTHMaximum options length for ECIES long format.- See Also:
OFF_FLAG_EC_SHORT
private static final int OFF_FLAG_EC_SHORTOffset for flags in ECIES short format.- See Also:
OFF_LAYER_ENC_TYPE
private static final int OFF_LAYER_ENC_TYPEOffset for layer encryption type in ECIES short format.- See Also:
OFF_REQ_TIME_EC_SHORT
private static final int OFF_REQ_TIME_EC_SHORTOffset for request time in ECIES short format.- See Also:
OFF_EXPIRATION_SHORT
private static final int OFF_EXPIRATION_SHORTOffset for expiration in ECIES short format.- See Also:
OFF_SEND_MSG_ID_EC_SHORT
private static final int OFF_SEND_MSG_ID_EC_SHORTOffset for send message ID in ECIES short format.- See Also:
OFF_OPTIONS_SHORT
private static final int OFF_OPTIONS_SHORTOffset for options in ECIES short format.- See Also:
LENGTH_EC_SHORT
private static final int LENGTH_EC_SHORTRecord length for ECIES short format (154 bytes).- See Also:
MAX_OPTIONS_LENGTH_SHORT
private static final int MAX_OPTIONS_LENGTH_SHORTMaximum options length for ECIES short format.- See Also:
ZEROLEN
private static final byte[] ZEROLENEmpty byte array for short record HKDF.INFO_1
HKDF info string for reply key derivation.- See Also:
INFO_2
HKDF info string for layer key derivation.- See Also:
INFO_3
HKDF info string for IV key derivation.- See Also:
INFO_4
HKDF info string for garlic key and tag derivation.- See Also:
TEST
TESTKF
Test key factory.
Constructor Details
BuildRequestRecord
public BuildRequestRecord(RouterContext ctx, PrivateKey ourKey, EncryptedBuildRecord encryptedRecord) throws DataFormatException Decrypts an encrypted build request record. Decrypt the data from the specified record, writing the decrypted record into this instance's data bufferCaller MUST check that first 16 bytes of our hash matches first 16 bytes of encryptedRecord before calling this. Not checked here.
The ChaCha reply key and IV will be available via the getters after this call if ourKey is ECIES.
- Parameters:
ctx- the router contextourKey- our private key to decrypt withencryptedRecord- the encrypted build record- Throws:
DataFormatException- on decrypt fail
BuildRequestRecord
public BuildRequestRecord(I2PAppContext ctx, long receiveTunnelId, Hash peer, long nextTunnelId, Hash nextHop, long nextMsgId, SessionKey layerKey, SessionKey ivKey, SessionKey replyKey, byte[] iv, boolean isInGateway, boolean isOutEndpoint) Creates a new ElGamal build request record. Populate this instance with data. A new buffer is created to contain the data, with the necessary randomized padding.ElGamal only. ECIES constructor below.
- Parameters:
ctx- the application contextreceiveTunnelId- tunnel the current hop will receive messages onpeer- current hop's identity, unused, no read() methodnextTunnelId- id for the next hop, or where we send the reply (if we are the outbound endpoint)nextHop- next hop's identity, or where we send the reply (if we are the outbound endpoint)nextMsgId- message ID to use when sending on to the next hop (or for the reply)layerKey- tunnel layer key to be used by the peerivKey- tunnel IV key to be used by the peerreplyKey- key to be used when encrypting the reply to this build requestiv- iv to be used when encrypting the reply to this build requestisInGateway- are we the gateway of an inbound tunnel?isOutEndpoint- are we the endpoint of an outbound tunnel?
BuildRequestRecord
public BuildRequestRecord(I2PAppContext ctx, long receiveTunnelId, long nextTunnelId, Hash nextHop, long nextMsgId, SessionKey layerKey, SessionKey ivKey, SessionKey replyKey, byte[] iv, boolean isInGateway, boolean isOutEndpoint, Properties options) Creates a new ECIES long build request record. Populate this instance with data. A new buffer is created to contain the data, with the necessary randomized padding.ECIES long record only. ElGamal constructor above.
- Parameters:
ctx- the application contextreceiveTunnelId- tunnel the current hop will receive messages onnextTunnelId- id for the next hop, or where we send the reply (if we are the outbound endpoint)nextHop- next hop's identity, or where we send the reply (if we are the outbound endpoint)nextMsgId- message ID to use when sending on to the next hop (or for the reply)layerKey- tunnel layer key to be used by the peerivKey- tunnel IV key to be used by the peerreplyKey- key to be used when encrypting the reply to this build requestiv- iv to be used when encrypting the reply to this build requestisInGateway- are we the gateway of an inbound tunnel?isOutEndpoint- are we the endpoint of an outbound tunnel?options- 296 bytes max when serialized- Throws:
IllegalArgumentException- if options too long
BuildRequestRecord
public BuildRequestRecord(I2PAppContext ctx, long receiveTunnelId, long nextTunnelId, Hash nextHop, long nextMsgId, boolean isInGateway, boolean isOutEndpoint, Properties options) Creates a new ECIES short build request record. Populate this instance with data. A new buffer is created to contain the data, with the necessary randomized padding.ECIES short record only. ElGamal constructor above.
- Parameters:
ctx- the application contextreceiveTunnelId- tunnel the current hop will receive messages onnextTunnelId- id for the next hop, or where we send the reply (if we are the outbound endpoint)nextHop- next hop's identity, or where we send the reply (if we are the outbound endpoint)nextMsgId- message ID to use when sending on to the next hop (or for the reply)isInGateway- are we the gateway of an inbound tunnel?isOutEndpoint- are we the endpoint of an outbound tunnel?options- 98 bytes max when serialized- Throws:
IllegalArgumentException- if options too long
Method Details
getData
public byte[] getData()Returns the raw record data.- Returns:
- 222 (ElG) or 464 (ECIES) bytes, non-null
readReceiveTunnelId
public long readReceiveTunnelId()Reads the tunnel ID this hop should receive messages on.- Returns:
- the tunnel ID
readNextTunnelId
public long readNextTunnelId()Reads the next hop's tunnel ID. What tunnel ID the next hop receives messages on. If this is the outbound tunnel endpoint, this specifies the tunnel ID to which the reply should be sent.- Returns:
- the next tunnel ID
readNextIdentity
Reads the next hop's identity hash. Read the next hop from the record. If this is the outbound tunnel endpoint, this specifies the gateway to which the reply should be sent.- Returns:
- the next hop's identity hash, non-null
readLayerKey
Reads the tunnel layer encryption key. Tunnel layer encryption key that the current hop should use.- Returns:
- the session key for layer encryption
readIVKey
Reads the tunnel IV encryption key. Tunnel IV encryption key that the current hop should use.- Returns:
- the session key for IV encryption
readReplyKey
Reads the reply encryption key. AES Session key that should be used to encrypt the reply. Not to be used for short ECIES records; use the ChaChaReplyKey instead.- Returns:
- the session key for reply encryption
- Throws:
IllegalStateException- for short ECIES records
readReplyIV
public byte[] readReplyIV()Reads the reply IV. AES IV that should be used to encrypt the reply. Not to be used for short ECIES records.- Returns:
- 16 bytes IV data
- Throws:
IllegalStateException- for short ECIES records
readIsInboundGateway
public boolean readIsInboundGateway()Reads whether this hop is an inbound gateway. The current hop is the inbound gateway. If this is true, it means anyone can send messages to this tunnel, but if it is false, only the current predecessor can.- Returns:
- true if inbound gateway, false otherwise
readIsOutboundEndpoint
public boolean readIsOutboundEndpoint()Reads whether this hop is an outbound endpoint. The current hop is the outbound endpoint. If this is true, the next identity and next tunnel fields refer to where the reply should be sent.- Returns:
- true if outbound endpoint, false otherwise
readRequestTime
public long readRequestTime()Reads the request time. For ElGamal, time that the request was sent (ms), truncated to the nearest hour. For ECIES, time that the request was sent (ms), truncated to the nearest minute. This ignores leap seconds.- Returns:
- the request time in milliseconds
readReplyMessageId
public long readReplyMessageId()Reads the reply message ID. What message ID should we send the request to the next hop with. If this is the outbound tunnel endpoint, this specifies the message ID with which the reply should be sent.- Returns:
- the reply message ID
readExpiration
public long readExpiration()Reads the expiration time. The expiration in milliseconds from now.- Returns:
- the expiration in milliseconds
readOptions
Reads the tunnel build options. ECIES only.- Returns:
- the properties, or null for ElGamal or on error
readLayerEncryptionType
public int readLayerEncryptionType()Reads the layer encryption type. ECIES short record only.- Returns:
- the encryption type (0-255), or 0 for ElGamal or ECIES long record
readGarlicKeys
Reads the garlic keys for OBEP. ECIES short OBEP record only.- Returns:
- the garlic keys, or null for ElGamal or ECIES long record or non-OBEP
encryptRecord
Encrypts the record using ElGamal. Encrypt the record to the specified peer. The result is formatted as:bytes 0-15: truncated SHA-256 of the current hop's identity (the toPeer parameter) bytes 15-527: ElGamal-2048 encrypted block
ElGamal only.- Parameters:
ctx- the application contexttoKey- the public key to encrypt totoPeer- the peer's identity hash- Returns:
- the encrypted build record, non-null
- Throws:
IllegalArgumentException- if key type is not ElGamal
encryptECIESRecord
Encrypts the record using ECIES. Encrypt the record to the specified peer. ECIES only. The ChaCha reply key and IV will be available via the getters after this call. For short records, derived keys will be available viareadLayerKey(), readIVKey(), and readGarlicKeys() after this call. See class javadocs for format. See proposals 152 and 157.- Parameters:
ctx- the router contexttoKey- the public key to encrypt totoPeer- the peer's identity hash- Returns:
- the encrypted build record, non-null
- Throws:
IllegalArgumentException- if key type is not ECIESIllegalStateException- on encryption failure
getChaChaReplyKey
Returns the ChaCha reply key. Valid after callingencryptECIESRecord(RouterContext, PublicKey, Hash)or after the decrypting constructor with an ECIES private key. See proposal 152.- Returns:
- the session key, or null if no ECIES encrypt/decrypt operation was performed
getChaChaReplyAD
public byte[] getChaChaReplyAD()Returns the ChaCha reply AD (Associated Data). Valid after calling encryptECIESRecord() or after the decrypting constructor with an ECIES private key. See proposal 152.- Returns:
- the AD data (32 bytes), or null if no ECIES encrypt/decrypt operation was performed
toString
Concise summary for log output: crypto type, hop role and tunnel IDs. No key material; no expiration (callers log elapsed or age deltas separately when relevant); no next-identity (callers print the peer hash in the message header). Starts with a newline and an asterisk for multi-line log entries.role
The hop's role in the tunnel, in the plain words the logs use instead of the IBGW / OBEP shorthands.- Parameters:
inboundGateway- true if this hop receives the tunnel from the clientoutboundEndpoint- true if this hop forwards it to the final peer- Returns:
- the role name, never null
toKeyString
Key material for DEBUG-level build interop debugging only. Never log this at INFO or above. Starts with a newline and an asterisk for multi-line log entries.- Returns:
- the key material dump, never null