All Implemented Interfaces:
Serializable, DataStructure

public class EncryptedLeaseSetextends LeaseSet2
Implementation of EncryptedLeaseSet as specified in Proposal 123: New NetDb Entries.

EncryptedLeaseSet provides privacy and authentication enhancements over standard LeaseSet2:

  • LeaseSet content is encrypted using authenticated encryption
  • Supports per-client and group-based access control
  • Uses blinded keys for enhanced privacy
  • Requires authentication data for decryption
  • Protects tunnel endpoints from unauthorized discovery

Key Features:

  • Authentication Types: Supports DH, PSK, and no authentication
  • Blinded Keys: Uses LeaseSet.getSigningKey() for the blinded key (revocation key in super)
  • Encryption: Content encrypted with ChaCha20-Poly1305 AEAD
  • Access Control: Fine-grained control over who can decrypt the LeaseSet

Usage:

  • Services requiring restricted access to tunnel endpoints
  • Private services with authenticated client access
  • Situations where tunnel endpoint discovery must be controlled

Authentication Methods:

Implementation Status: PRELIMINARY - Subject to change as the proposal evolves.

See Also:
  • Field Details

    • _encryptedData

      private byte[] _encryptedData
      Includes salt.
    • _decryptedLS2

      private LeaseSet2 _decryptedLS2
      Decrypted LeaseSet 2 instance.
    • __calculatedHash

      private Hash __calculatedHash
      Cached calculated hash value.
    • _alpha

      private SigningPrivateKey _alpha
      Alpha signing private key.
    • _unblindedSPK

      private SigningPublicKey _unblindedSPK
      To decrypt with if we don't have the full destination.
    • _secret

      private String _secret
      Secret passphrase for decryption.
    • _clientPrivateKey

      private PrivateKey _clientPrivateKey
      Client private key for decryption.
    • _log

      private final Log _log
      Logger instance.
    • _authType

      private int _authType
      Authorization type of this lease set.
    • _numKeys

      private int _numKeys
      Number of keys in the encrypted set.
    • MIN_ENCRYPTED_SIZE

      private static final int MIN_ENCRYPTED_SIZE
      Minimum encrypted data size (salt + IV).
      See Also:
    • MAX_ENCRYPTED_SIZE

      private static final int MAX_ENCRYPTED_SIZE
      Maximum encrypted data size.
      See Also:
    • SALT_LEN

      private static final int SALT_LEN
      Salt length in bytes.
      See Also:
    • CREDENTIAL

      private static final byte[] CREDENTIAL
      Credential ASCII bytes.
    • SUBCREDENTIAL

      private static final byte[] SUBCREDENTIAL
      Subcredential ASCII bytes.
    • ELS2L1K

      private static final String ELS2L1K
      ELS2 level 1 key label.
      See Also:
    • ELS2L2K

      private static final String ELS2L2K
      ELS2 level 2 key label.
      See Also:
    • ELS2_DH

      private static final String ELS2_DH
      ELS2 Diffie-Hellman key label.
      See Also:
    • ELS2_PSK

      private static final String ELS2_PSK
      ELS2 pre-shared key label.
      See Also:
    • IV_LEN

      private static final int IV_LEN
      AES-GCM initialization vector length.
      See Also:
    • ID_LEN

      private static final int ID_LEN
      Client identifier length in bytes.
      See Also:
    • CLIENT_LEN

      private static final int CLIENT_LEN
      Combined client ID and cookie length.
      See Also:
    • _hkdf

      private static volatile HKDF _hkdf
      Cached HKDF for layer encryption/decryption. HKDF is stateless (it only holds the context, and the context's HMAC256Generator is itself thread-safe), so one instance per context is reusable by all client threads and saves an allocation per encrypt/decrypt.
    • _hkdfCtx

      private static volatile I2PAppContext _hkdfCtx
      The context _hkdf was built for, so a context change forces a rebuild.
  • Constructor Details

    • EncryptedLeaseSet

      public EncryptedLeaseSet()
      Creates a new EncryptedLeaseSet with default values.
  • Method Details

    • hkdf

      private static HKDF hkdf(I2PAppContext ctx)
      Get the shared HKDF for a context. The cached instance is rebuilt if the context differs, so a context swap never leaves a HKDF bound to a stale one. A racy double build is harmless, as both instances are equivalent.
      Parameters:
      ctx - the app context
      Returns:
      the shared HKDF, never null
    • getDecryptedLeaseSet

      public LeaseSet2 getDecryptedLeaseSet()
      Leaseset or null if not decrypted.
      Returns:
      leaseset or null if not decrypted.
    • setSecret

      public void setSecret(String secret)
      Must be set before sign or verify. Must be called before setDestination(Destination) or setSigningKey(), or alpha will be wrong.
      Parameters:
      secret - null or "" for none (default)
    • setClientPrivateKey

      public void setClientPrivateKey(PrivateKey privKey)
      Must be set before verify for per-client auth.
      Parameters:
      privKey - non-null
    • getType

      public int getType()
      Entry type for the network database.
      Overrides:
      getType in class LeaseSet2
      Returns:
      KEY_TYPE_ENCRYPTED_LS2 or KEY_TYPE_LS2
    • getLeaseCount

      public int getLeaseCount()
      0-16, or 0 if not decrypted.
      Overrides:
      getLeaseCount in class LeaseSet
      Returns:
      0-16, or 0 if not decrypted.
    • getLease

      public Lease getLease(int index)
      Null if not decrypted.
      Overrides:
      getLease in class LeaseSet
      Parameters:
      index - the lease index
      Returns:
      null if not decrypted.
    • getEncryptionKeys

      public List<PublicKey> getEncryptionKeys()
      Null if not decrypted.
      Overrides:
      getEncryptionKeys in class LeaseSet2
      Returns:
      null if not decrypted.
    • getEncryptionKey

      public PublicKey getEncryptionKey(Set<EncType> supported)
      If more than one key, return the first supported one. If none supported, return null.
      Overrides:
      getEncryptionKey in class LeaseSet2
      Parameters:
      supported - what return types are allowed
      Returns:
      first supported key or null
    • setDestination

      public void setDestination(Destination dest)
      Overridden to set the blinded key. setSecret(String) MUST be called before this for non-null secret, or alpha will be wrong.
      Overrides:
      setDestination in class LeaseSet
      Parameters:
      dest - non-null, must be EdDSA_SHA512_Ed25519 or RedDSA_SHA512_Ed25519
      Throws:
      IllegalStateException - if already signed
      IllegalArgumentException - if not EdDSA
    • setSigningKey

      public void setSigningKey(SigningPublicKey spk)
      Overridden to set the blinded key. setSecret() MUST be called before this for non-null secret, or alpha will be wrong.
      Overrides:
      setSigningKey in class LeaseSet2
      Parameters:
      spk - unblinded key non-null, must be EdDSA_SHA512_Ed25519 or RedDSA_SHA512_Ed25519
      Throws:
      IllegalStateException - if already signed
      IllegalArgumentException - if not EdDSA
    • blind

      private SigningPublicKey blind(SigningPublicKey spk)
      Generate blinded pubkey from the unblinded pubkey in the destination, which must have been previously set.
      Parameters:
      spk - the unblinded signing public key from the destination
      Returns:
      the blinded public key
    • getSigningPublicKey

      protected SigningPublicKey getSigningPublicKey()
      Overridden to return the blinded key so super.verifySignature() will work.
      Overrides:
      getSigningPublicKey in class DatabaseEntry
      Returns:
      SPK or null
    • readBytes

      public void readBytes(InputStream in) throws DataFormatException, IOException
      This does NOT validate the signature.
      Specified by:
      readBytes in interface DataStructure
      Overrides:
      readBytes in class LeaseSet2
      Parameters:
      in - stream to read from
      Throws:
      IllegalStateException - if called more than once or Destination already set
      DataFormatException - if the data is improperly formatted
      IOException - if there was a problem reading the stream
    • writeBytesWithoutSig

      protected void writeBytesWithoutSig(OutputStream out) throws DataFormatException, IOException
      Before encrypt(SessionKey) is called, the inner leaseset. After encrypt() is called, the encrypted data. Without sig. This does NOT validate the signature.
      Overrides:
      writeBytesWithoutSig in class LeaseSet2
      Parameters:
      out - the stream to write the header and body to
      Throws:
      DataFormatException - if the destination or encryption key is unset
      IOException - if the stream cannot be written
    • verifyOfflineSignature

      public boolean verifyOfflineSignature()
      Overridden because we have a blinded key, not a dest.
      Overrides:
      verifyOfflineSignature in class LeaseSet2
      Returns:
      true if valid
    • readHeader

      protected void readHeader(InputStream in) throws DataFormatException, IOException
      Overridden because we have a blinded key, not a dest.
      Overrides:
      readHeader in class LeaseSet2
      Parameters:
      in - the input stream
      Throws:
      DataFormatException - if the data is invalid
      IOException - if there is an error reading
    • writeHeader

      protected void writeHeader(OutputStream out) throws DataFormatException, IOException
      Overridden because we have a blinded key, not a dest.
      Overrides:
      writeHeader in class LeaseSet2
      Parameters:
      out - the output stream
      Throws:
      DataFormatException - if the data is invalid
      IOException - if there is an error writing
    • readOfflineBytes

      protected void readOfflineBytes(InputStream in) throws DataFormatException, IOException
      Overridden because we have a blinded key, not a dest.
      Overrides:
      readOfflineBytes in class LeaseSet2
      Parameters:
      in - the input stream
      Throws:
      DataFormatException - if the data is invalid
      IOException - if there is an error reading
    • writeOfflineBytes

      protected void writeOfflineBytes(OutputStream out) throws DataFormatException, IOException
      Overridden because we have a blinded key, not a dest.
      Overrides:
      writeOfflineBytes in class LeaseSet2
      Parameters:
      out - the output stream
      Throws:
      DataFormatException - if the data is invalid
      IOException - if there is an error writing
    • size

      public int size()
      Number of bytes, NOT including signature.
      Overrides:
      size in class LeaseSet2
      Returns:
      the size in bytes
    • getHash

      public Hash getHash()
      This must be used instead of getDestination().getHash().

      Overridden because we have a blinded key, not a dest. This is the hash of the signing public key type and the signing public key. Throws IllegalStateException if not initialized.

      Overrides:
      getHash in class DatabaseEntry
      Returns:
      the hash of the signing public key's type and key, not the destination hash
      Throws:
      IllegalStateException - if the signing key is not set
    • encrypt

      public void encrypt(SessionKey skey)
      Throws IllegalStateException if not initialized.
      Overrides:
      encrypt in class LeaseSet2
      Parameters:
      skey - unused in this implementation
      Throws:
      IllegalStateException - if the lease set is already encrypted or not signed
    • encrypt

      public void encrypt(int authType, List<? extends SimpleDataStructure> clientKeys)
      Throws IllegalStateException if not initialized. Ref: proposal 123.
      Parameters:
      authType - 0, 1, or 3, see BlindData
      clientKeys - The client's X25519 public or private keys, null if unused
      Throws:
      IllegalStateException - if already encrypted, not signed, or the inner layer cannot be written
    • decrypt

      private void decrypt(PrivateKey csk) throws DataFormatException, IOException
      Throws IllegalStateException if not initialized.
      Parameters:
      csk - PrivateKey for DH or PSK, or null if none
      Throws:
      IllegalStateException - if this object holds no encrypted data
      DataFormatException - if the per-client auth entry is missing or unusable, or the decrypted data is not a valid LeaseSet
      IOException - if the decrypted inner LeaseSet cannot be read
    • x_decrypt

      private void x_decrypt(PrivateKey csk) throws DataFormatException, IOException
      Throws IllegalStateException if not initialized.
      Parameters:
      csk - PrivateKey for DH or PSK, or null if none
      Throws:
      IllegalStateException - if this object holds no encrypted data
      DataFormatException - if the per-client auth type or entry is missing or unusable, or the decrypted data is not a valid LeaseSet
      IOException - if the decrypted inner LeaseSet cannot be read
    • getHKDFInput

      private byte[] getHKDFInput(I2PAppContext ctx)
      The HKDF input (no per-client auth).
      Parameters:
      ctx - the context supplying the router and client keys used to derive the subcredential
      Returns:
      36 bytes
    • getHKDFInput

      private byte[] getHKDFInput(I2PAppContext ctx, byte[] authcookie)
      The HKDF input (with per-client auth).
      Parameters:
      ctx - the context supplying the keys used to derive the subcredential
      authcookie - 32 bytes
      Returns:
      68 bytes
    • getSubcredential

      private byte[] getSubcredential(I2PAppContext ctx)
      The subcredential.
      Parameters:
      ctx - the context supplying the hash used to derive it
      Returns:
      32 bytes
      Throws:
      IllegalStateException - if we don't have it
    • hash

      private static byte[] hash(I2PAppContext ctx, byte[] p, byte[] d)
      Hash with a personalization string.
      Parameters:
      ctx - the context supplying the SHA implementation
      p - the personalization string prepended to the data
      d - the data to hash
      Returns:
      32 bytes
    • sign

      public void sign(SigningPrivateKey key) throws DataFormatException
      Sign the structure using the supplied signing key. Overridden because we sign the inner, then blind and encrypt and sign the outer.
      Overrides:
      sign in class LeaseSet2
      Parameters:
      key - the signing key
      Throws:
      IllegalStateException - if already signed
      DataFormatException - if signing fails
    • sign

      public void sign(SigningPrivateKey key, int authType, List<? extends SimpleDataStructure> clientKeys) throws DataFormatException
      Sign the structure using the supplied signing key. Overridden because we sign the inner, then blind and encrypt and sign the outer.
      Parameters:
      key - the signing key
      authType - 0, 1, or 3, see BlindData
      clientKeys - X25519 public keys for DH, private keys for PSK
      Throws:
      IllegalStateException - if already signed
      DataFormatException - if the inner bytes cannot be serialized, or the blinded key is not one of the supported signing key types
    • verifySignature

      public boolean verifySignature()
      Overridden to decrypt if possible, and verify inner sig also.

      Must call setDestination() prior to this if attempting decryption. Must call setClientKey() prior to this if attempting decryption.

      Overrides:
      verifySignature in class LeaseSet2
      Returns:
      true if the signature is valid, false if it does not verify
    • verifySignature

      public boolean verifySignature(PrivateKey clientKey)
      Decrypt if possible, and verify inner sig also.

      Must call setDestination() prior to this if attempting decryption.

      Parameters:
      clientKey - PrivateKey for DH or PSK, or null if none
      Returns:
      true if the signature is valid, false if it does not verify
    • equals

      public boolean equals(Object object)
      Compares this EncryptedLeaseSet with another object for equality.
      Overrides:
      equals in class LeaseSet2
    • hashCode

      public int hashCode()
      The destination has enough randomness in it to use it by itself for speed.
      Overrides:
      hashCode in class LeaseSet2
    • toString

      public String toString()
      Returns a string representation of this EncryptedLeaseSet.
      Overrides:
      toString in class LeaseSet2