I2CP: Encrypted LS2 handling fixes, log tweaks (WIP)

Add number of privkeys field to CreateLeaseSet2 message
Check all privkeys, not just the first, on router side
This commit is contained in:
zzz
2019-03-02 19:53:16 +00:00
parent 335736b2b7
commit 7cbb43ab75
5 changed files with 159 additions and 44 deletions

View File

@ -268,8 +268,9 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
}
} else {
leaseSet.setEncryptionKey(li.getPublicKey());
// revocation key
leaseSet.setSigningKey(li.getSigningPublicKey());
}
leaseSet.setSigningKey(li.getSigningPublicKey());
// SubSession options aren't updated via the gui, so use the primary options
Properties opts;
if (session instanceof SubSession)

View File

@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.crypto.Blinding;
@ -68,7 +69,6 @@ public class EncryptedLeaseSet extends LeaseSet2 {
*/
@Override
public int getLeaseCount() {
// TODO attempt decryption
return _decryptedLS2 != null ? _decryptedLS2.getLeaseCount() : 0;
}
@ -77,10 +77,19 @@ public class EncryptedLeaseSet extends LeaseSet2 {
*/
@Override
public Lease getLease(int index) {
// TODO attempt decryption
return _decryptedLS2 != null ? _decryptedLS2.getLease(index) : null;
}
/**
* @return null if not decrypted.
* @since 0.9.39
*/
public List<PublicKey> getEncryptionKeys() {
if (_decryptedLS2 != null)
return _decryptedLS2.getEncryptionKeys();
return super.getEncryptionKeys();
}
/**
* Overridden to set the blinded key
*
@ -105,7 +114,9 @@ public class EncryptedLeaseSet extends LeaseSet2 {
if (_signingKey == null)
_signingKey = bpk;
else if (!_signingKey.equals(bpk))
throw new IllegalArgumentException("blinded pubkey mismatch");
throw new IllegalArgumentException("blinded pubkey mismatch:" +
"\nas received: " + _signingKey +
"\nas calculated: " + bpk);
}
/**
@ -121,7 +132,13 @@ public class EncryptedLeaseSet extends LeaseSet2 {
_alpha = Blinding.generateAlpha(ctx, _destination, null);
else
_alpha = Blinding.generateAlpha(ctx, _destination, null, _published);
return Blinding.blind(spk, _alpha);
SigningPublicKey rv = Blinding.blind(spk, _alpha);
if (_log.shouldDebug())
_log.debug("Blind:" +
"\norig: " + spk +
"\nalpha: " + _alpha +
"\nblinded: " + rv);
return rv;
}
/**
@ -348,6 +365,10 @@ public class EncryptedLeaseSet extends LeaseSet2 {
plaintext = ciphertext;
ciphertext = new byte[SALT_LEN + plaintext.length];
System.arraycopy(salt, 0, ciphertext, 0, SALT_LEN);
if (_log.shouldDebug()) {
_log.debug("Encrypt: chacha20 key:\n" + net.i2p.util.HexDump.dump(key));
_log.debug("Encrypt: chacha20 IV:\n" + net.i2p.util.HexDump.dump(iv));
}
ChaCha20.encrypt(key, iv, plaintext, 0, ciphertext, SALT_LEN, plaintext.length);
if (_log.shouldDebug())
_log.debug("Encrypt: outer ciphertext:\n" + net.i2p.util.HexDump.dump(ciphertext));
@ -377,6 +398,10 @@ public class EncryptedLeaseSet extends LeaseSet2 {
byte[] plaintext = new byte[ciphertext.length - SALT_LEN];
// first 32 bytes of ciphertext are the salt
hkdf.calculate(ciphertext, input, ELS2L1K, key, iv, 0);
if (_log.shouldDebug()) {
_log.debug("Decrypt: chacha20 key:\n" + net.i2p.util.HexDump.dump(key));
_log.debug("Decrypt: chacha20 IV:\n" + net.i2p.util.HexDump.dump(iv));
}
ChaCha20.decrypt(key, iv, ciphertext, SALT_LEN, plaintext, 0, plaintext.length);
if (_log.shouldDebug()) {
_log.debug("Decrypt: outer ciphertext:\n" + net.i2p.util.HexDump.dump(ciphertext));
@ -477,8 +502,8 @@ public class EncryptedLeaseSet extends LeaseSet2 {
_flags = saveFlags;
if (_log.shouldDebug()) {
_log.debug("Sign inner with key: " + key.getType() + ' ' + key.toBase64());
_log.debug("Corresponding pubkey: " + key.toPublic().toBase64());
_log.debug("Sign inner: " + _signature.getType() + ' ' + _signature.toBase64());
_log.debug("Corresponding pubkey: " + key.toPublic());
_log.debug("Inner sig: " + _signature.getType() + ' ' + _signature.toBase64());
}
encrypt(null);
SigningPrivateKey bkey = Blinding.blind(key, _alpha);
@ -498,8 +523,8 @@ public class EncryptedLeaseSet extends LeaseSet2 {
throw new DataFormatException("Signature failed with " + key.getType() + " key");
if (_log.shouldDebug()) {
_log.debug("Sign outer with key: " + bkey.getType() + ' ' + bkey.toBase64());
_log.debug("Corresponding pubkey: " + bkey.toPublic().toBase64());
_log.debug("Sign outer: " + _signature.getType() + ' ' + _signature.toBase64());
_log.debug("Corresponding pubkey: " + bkey.toPublic());
_log.debug("Outer sig: " + _signature.getType() + ' ' + _signature.toBase64());
}
}
@ -514,7 +539,7 @@ public class EncryptedLeaseSet extends LeaseSet2 {
public boolean verifySignature() {
if (_log.shouldDebug()) {
_log.debug("Sig verify outer with key: " + _signingKey.getType() + ' ' + _signingKey.toBase64());
_log.debug("Sig verify outer: " + _signature.getType() + ' ' + _signature.toBase64());
_log.debug("Outer sig: " + _signature.getType() + ' ' + _signature.toBase64());
}
if (!super.verifySignature()) {
_log.warn("ELS2 outer sig verify fail");
@ -537,7 +562,7 @@ public class EncryptedLeaseSet extends LeaseSet2 {
if (_log.shouldDebug()) {
_log.debug("Decrypted inner LS2:\n" + _decryptedLS2);
_log.debug("Sig verify inner with key: " + _decryptedLS2.getDestination().getSigningPublicKey().getType() + ' ' + _decryptedLS2.getDestination().getSigningPublicKey().toBase64());
_log.debug("Sig verify inner: " + _decryptedLS2.getSignature().getType() + ' ' + _decryptedLS2.getSignature().toBase64());
_log.debug("Inner sig: " + _decryptedLS2.getSignature().getType() + ' ' + _decryptedLS2.getSignature().toBase64());
}
boolean rv = _decryptedLS2.verifySignature();
if (!rv)

View File

@ -16,6 +16,7 @@ import net.i2p.crypto.EncType;
import net.i2p.crypto.SigAlgo;
import net.i2p.crypto.SigType;
import net.i2p.util.Clock;
import net.i2p.util.Log;
import net.i2p.util.OrderedProperties;
/**
@ -256,6 +257,19 @@ public class LeaseSet2 extends LeaseSet {
return KEY_TYPE_LS2;
}
/**
* The revocation key. Overridden to do nothing,
* as we're using the _signingKey field for the blinded key in Enc LS2.
*
* @since 0.9.39
*/
@Override
public void setSigningKey(SigningPublicKey key) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(LeaseSet2.class);
if (log.shouldWarn())
log.warn("Don't set revocation key in ls2", new Exception("I did it"));
}
/** without sig! */
@Override
protected byte[] getBytes() {

View File

@ -115,18 +115,32 @@ public class CreateLeaseSet2Message extends CreateLeaseSetMessage {
type == DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2) {
LeaseSet2 ls2 = (LeaseSet2) _leaseSet;
// get one PrivateKey for each PublicKey
// TODO decrypt an encrypted LS so we can get the keys
List<PublicKey> pks = ls2.getEncryptionKeys();
if (pks == null)
throw new I2CPMessageException("TODO decrypt");
for (PublicKey pk : pks) {
EncType etype = pk.getType();
if (etype == null)
throw new I2CPMessageException("Unsupported encryption type");
int numkeys = in.read();
// pks is null for encrypted LS2
if (pks != null && numkeys != pks.size())
throw new I2CPMessageException("Wrong number of privkeys");
for (int i = 0; i < numkeys; i++) {
int encType = (int) DataHelper.readLong(in, 2);
int encLen = (int) DataHelper.readLong(in, 2);
if (encType != etype.getCode() || encLen != etype.getPrivkeyLen())
throw new I2CPMessageException("Enc type mismatch");
EncType etype;
if (pks != null) {
// standard LS2
etype = pks.get(i).getType();
if (etype == null)
throw new I2CPMessageException("Unsupported encryption type: " + encType);
if (encType != etype.getCode())
throw new I2CPMessageException("Enc type mismatch");
if (encLen != etype.getPrivkeyLen())
throw new I2CPMessageException("Enc type bad length");
} else {
// encrypted LS2
etype = EncType.getByCode(encType);
if (etype == null)
throw new I2CPMessageException("Unsupported encryption type: " + encType);
if (encLen != etype.getPrivkeyLen())
throw new I2CPMessageException("Enc type bad length");
}
PrivateKey priv = new PrivateKey(etype);
priv.readBytes(in);
addPrivateKey(priv);
@ -164,7 +178,9 @@ public class CreateLeaseSet2Message extends CreateLeaseSetMessage {
os.write(_leaseSet.getType());
_leaseSet.writeBytes(os);
if (type != DatabaseEntry.KEY_TYPE_META_LS2) {
for (PrivateKey pk : getPrivateKeys()) {
List<PrivateKey> pks = getPrivateKeys();
os.write(pks.size());
for (PrivateKey pk : pks) {
EncType etype = pk.getType();
DataHelper.writeLong(os, 2, etype.getCode());
DataHelper.writeLong(os, 2, pk.length());
@ -187,7 +203,9 @@ public class CreateLeaseSet2Message extends CreateLeaseSetMessage {
StringBuilder buf = new StringBuilder();
buf.append("[CreateLeaseSet2Message: ");
buf.append("\n\tLeaseSet: ").append(_leaseSet);
if (_leaseSet.getType() != DatabaseEntry.KEY_TYPE_META_LS2) {
int type = _leaseSet.getType();
if (type != DatabaseEntry.KEY_TYPE_META_LS2 &&
type != DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2) {
for (PrivateKey pk : getPrivateKeys()) {
buf.append("\n\tPrivateKey: ").append(pk);
}