From 8484a22fc4f2be4fab355f3628f12c3da3f500f1 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Wed, 23 Oct 2019 12:11:17 +0000 Subject: [PATCH] Router: Add KeyManager support for multiple leaseset private keys --- .../java/src/net/i2p/router/KeyManager.java | 23 +++- .../java/src/net/i2p/router/LeaseSetKeys.java | 102 +++++++++++++++++- 2 files changed, 119 insertions(+), 6 deletions(-) diff --git a/router/java/src/net/i2p/router/KeyManager.java b/router/java/src/net/i2p/router/KeyManager.java index b3d9687862..3b418e27e9 100644 --- a/router/java/src/net/i2p/router/KeyManager.java +++ b/router/java/src/net/i2p/router/KeyManager.java @@ -15,6 +15,7 @@ import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -110,15 +111,29 @@ public class KeyManager { public synchronized SigningPublicKey getSigningPublicKey() { return _signingPublicKey; } /** - * client + * Client with a single key + * * @param leaseRevocationPrivateKey unused, may be null */ public void registerKeys(Destination dest, SigningPrivateKey leaseRevocationPrivateKey, PrivateKey endpointDecryptionKey) { - if (_log.shouldLog(Log.INFO)) - _log.info("Registering keys for destination " + dest.calculateHash().toBase64()); + if (_log.shouldInfo()) + _log.info("Registering keys for destination " + dest.toBase32()); LeaseSetKeys keys = new LeaseSetKeys(dest, leaseRevocationPrivateKey, endpointDecryptionKey); _leaseSetKeys.put(dest.calculateHash(), keys); } + + /** + * Client with multiple keys + * + * @param leaseRevocationPrivateKey unused, may be null + * @since 0.9.44 + */ + public void registerKeys(Destination dest, SigningPrivateKey leaseRevocationPrivateKey, List<PrivateKey> endpointDecryptionKeys) { + if (_log.shouldInfo()) + _log.info("Registering keys for destination " + dest.toBase32()); + LeaseSetKeys keys = new LeaseSetKeys(dest, leaseRevocationPrivateKey, endpointDecryptionKeys); + _leaseSetKeys.put(dest.calculateHash(), keys); + } /** * Read/Write the router keys from/to disk @@ -129,7 +144,7 @@ public class KeyManager { /** client */ public LeaseSetKeys unregisterKeys(Destination dest) { - if (_log.shouldLog(Log.INFO)) + if (_log.shouldInfo()) _log.info("Unregistering keys for destination " + dest.calculateHash().toBase64()); return _leaseSetKeys.remove(dest.calculateHash()); } diff --git a/router/java/src/net/i2p/router/LeaseSetKeys.java b/router/java/src/net/i2p/router/LeaseSetKeys.java index 75556d817f..ac623c05e7 100644 --- a/router/java/src/net/i2p/router/LeaseSetKeys.java +++ b/router/java/src/net/i2p/router/LeaseSetKeys.java @@ -8,6 +8,12 @@ package net.i2p.router; * */ +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import net.i2p.crypto.EncType; import net.i2p.data.Destination; import net.i2p.data.PrivateKey; import net.i2p.data.SigningPrivateKey; @@ -19,15 +25,66 @@ import net.i2p.data.SigningPrivateKey; public class LeaseSetKeys { private final SigningPrivateKey _revocationKey; private final PrivateKey _decryptionKey; + private final PrivateKey _decryptionKeyEC; + + /** + * Unmodifiable, ElGamal only + * @since 0.9.44 + */ + public static final Set<EncType> SET_ELG = Collections.unmodifiableSet(EnumSet.of(EncType.ELGAMAL_2048)); + private static final Set<EncType> SET_EC = Collections.unmodifiableSet(EnumSet.of(EncType.ECIES_X25519)); + private static final Set<EncType> SET_BOTH = Collections.unmodifiableSet(EnumSet.of(EncType.ELGAMAL_2048, EncType.ECIES_X25519)); + private static final Set<EncType> SET_NONE = Collections.unmodifiableSet(EnumSet.noneOf(EncType.class)); /** + * Client with a single key + * * @param dest unused * @param revocationKey unused, may be null * @param decryptionKey non-null */ public LeaseSetKeys(Destination dest, SigningPrivateKey revocationKey, PrivateKey decryptionKey) { - _revocationKey = revocationKey; - _decryptionKey = decryptionKey; + _revocationKey = revocationKey; + EncType type = decryptionKey.getType(); + if (type == EncType.ELGAMAL_2048) { + _decryptionKey = decryptionKey; + _decryptionKeyEC = null; + } else if (type == EncType.ECIES_X25519) { + _decryptionKey = null; + _decryptionKeyEC = decryptionKey; + } else { + throw new IllegalArgumentException("Unknown type " + type); + } + } + + /** + * Client with multiple keys + * + * @param dest unused + * @param revocationKey unused, may be null + * @param decryptionKeys non-null + * @since 0.9.44 + */ + public LeaseSetKeys(Destination dest, SigningPrivateKey revocationKey, List<PrivateKey> decryptionKeys) { + _revocationKey = revocationKey; + PrivateKey elg = null; + PrivateKey ec = null; + for (PrivateKey pk : decryptionKeys) { + EncType type = pk.getType(); + if (type == EncType.ELGAMAL_2048) { + if (elg != null) + throw new IllegalArgumentException("Multiple keys same type"); + elg = pk; + } else if (type == EncType.ECIES_X25519) { + if (ec != null) + throw new IllegalArgumentException("Multiple keys same type"); + ec = pk; + } else { + throw new IllegalArgumentException("Unknown type " + type); + } + } + _decryptionKey = elg; + _decryptionKeyEC = ec; } /** @@ -43,7 +100,48 @@ public class LeaseSetKeys { * know on what router the destination is connected and as such can't encrypt * to that router's normal public key. * + * @return ElGamal key or null if the LS does not support ElGamal */ public PrivateKey getDecryptionKey() { return _decryptionKey; } + /** + * Decryption key which can open up garlic messages encrypted to the + * LeaseSet's public key. This is used because the general public does not + * know on what router the destination is connected and as such can't encrypt + * to that router's normal public key. + * + * @return key of the specified type or null if the LS does not support that type + * @since 0.9.44 + */ + public PrivateKey getDecryptionKey(EncType type) { + if (type == EncType.ELGAMAL_2048) + return _decryptionKey; + if (type == EncType.ECIES_X25519) + return _decryptionKeyEC; + return null; + } + + /** + * Do we support this type of encryption? + * + * @since 0.9.44 + */ + public boolean isSupported(EncType type) { + if (type == EncType.ELGAMAL_2048) + return _decryptionKey != null; + if (type == EncType.ECIES_X25519) + return _decryptionKeyEC != null; + return false; + } + + /** + * What types of encryption are supported? + * + * @since 0.9.44 + */ + public Set<EncType> getSupportedEncryption() { + if (_decryptionKey != null) + return (_decryptionKeyEC != null) ? SET_BOTH : SET_ELG; + return (_decryptionKeyEC != null) ? SET_EC : SET_NONE; + } } -- GitLab