From e9ec043bf4ea80e2a26fbeaa72ca42f028a0bf89 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Sat, 13 Oct 2018 14:36:39 +0000 Subject: [PATCH] Data: Encrypted LS2, other LS2 changes --- .../src/net/i2p/data/EncryptedLeaseSet.java | 195 ++++++++++++++++++ core/java/src/net/i2p/data/LeaseSet2.java | 8 +- core/java/src/net/i2p/data/MetaLeaseSet.java | 8 - 3 files changed, 201 insertions(+), 10 deletions(-) create mode 100644 core/java/src/net/i2p/data/EncryptedLeaseSet.java diff --git a/core/java/src/net/i2p/data/EncryptedLeaseSet.java b/core/java/src/net/i2p/data/EncryptedLeaseSet.java new file mode 100644 index 0000000000..23de3e9453 --- /dev/null +++ b/core/java/src/net/i2p/data/EncryptedLeaseSet.java @@ -0,0 +1,195 @@ +package net.i2p.data; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import net.i2p.crypto.SigType; +import net.i2p.util.Clock; + +/** + * Use getSigningKey() / setSigningKey() (revocation key in super) for the blinded key. + * + * PRELIMINARY - Subject to change - see proposal 123 + * + * @since 0.9.38 + */ +public class EncryptedLeaseSet extends LeaseSet2 { + + // includes IV and MAC + private byte[] _encryptedData; + + private static final int MIN_ENCRYPTED_SIZE = 8 + 16; + private static final int MAX_ENCRYPTED_SIZE = 4096; + + public EncryptedLeaseSet() { + super(); + } + + ///// overrides below here + + @Override + public int getType() { + return KEY_TYPE_ENCRYPTED_LS2; + } + + /** + * This does NOT validate the signature + * + * @throws IllegalStateException if called more than once or Destination already set + */ + @Override + public void readBytes(InputStream in) throws DataFormatException, IOException { + if (_signingKey != null) + throw new IllegalStateException(); + // LS2 header + readHeader(in); + // Encrypted LS2 part + int encryptedSize = (int) DataHelper.readLong(in, 2); + if (encryptedSize < MIN_ENCRYPTED_SIZE || + encryptedSize > MAX_ENCRYPTED_SIZE) + throw new DataFormatException("bad LS size: " + encryptedSize); + _encryptedData = new byte[encryptedSize]; + DataHelper.read(in, _encryptedData); + // signature type depends on offline or not + SigType type = isOffline() ? _transientSigningPublicKey.getType() : _signingKey.getType(); + _signature = new Signature(type); + _signature.readBytes(in); + } + + /** + * Without sig. This does NOT validate the signature + */ + @Override + protected void writeBytesWithoutSig(OutputStream out) throws DataFormatException, IOException { + if (_signingKey == null) + throw new DataFormatException("Not enough data to write out a LeaseSet"); + // LS2 header + writeHeader(out); + // Encrypted LS2 part + DataHelper.writeLong(out, 2, _encryptedData.length); + out.write(_encryptedData); + } + + /** + * Overridden because we have a blinded key, not a dest + */ + @Override + public boolean verifyOfflineSignature() { + return verifyOfflineSignature(_signingKey); + } + + /** + * Overridden because we have a blinded key, not a dest + */ + @Override + protected void readHeader(InputStream in) throws DataFormatException, IOException { + int stype = (int) DataHelper.readLong(in, 2); + SigType type = SigType.getByCode(stype); + if (type == null) + throw new DataFormatException("unknown key type " + stype); + _signingKey = new SigningPublicKey(type); + _signingKey.readBytes(in); + _published = DataHelper.readLong(in, 4) * 1000; + _expires = _published + (DataHelper.readLong(in, 2) * 1000); + _flags = (int) DataHelper.readLong(in, 2); + if (isOffline()) + readOfflineBytes(in); + } + + /** + * Overridden because we have a blinded key, not a dest + */ + @Override + protected void writeHeader(OutputStream out) throws DataFormatException, IOException { + DataHelper.writeLong(out, 2, _signingKey.getType().getCode()); + _signingKey.writeBytes(out); + if (_published <= 0) + _published = Clock.getInstance().now(); + DataHelper.writeLong(out, 4, _published / 1000); + DataHelper.writeLong(out, 2, (_expires - _published) / 1000); + DataHelper.writeLong(out, 2, _flags); + if (isOffline()) + writeOfflineBytes(out); + } + + /** + * Overridden because we have a blinded key, not a dest + */ + @Override + protected void readOfflineBytes(InputStream in) throws DataFormatException, IOException { + _transientExpires = DataHelper.readLong(in, 4) * 1000; + int itype = (int) DataHelper.readLong(in, 2); + SigType type = SigType.getByCode(itype); + if (type == null) + throw new DataFormatException("Unknown sig type " + itype); + _transientSigningPublicKey = new SigningPublicKey(type); + _transientSigningPublicKey.readBytes(in); + SigType stype = _signingKey.getType(); + _offlineSignature = new Signature(stype); + _offlineSignature.readBytes(in); + } + + /** + * Overridden because we have a blinded key, not a dest + */ + @Override + protected void writeOfflineBytes(OutputStream out) throws DataFormatException, IOException { + if (_transientSigningPublicKey == null || _offlineSignature == null) + throw new DataFormatException("No offline key/sig"); + DataHelper.writeLong(out, 4, _transientExpires / 1000); + DataHelper.writeLong(out, 2, _signingKey.getType().getCode()); + _transientSigningPublicKey.writeBytes(out); + _offlineSignature.writeBytes(out); + } + + /** + * Number of bytes, NOT including signature + */ + @Override + public int size() { + int rv = _signingKey.length() + + 12 + + _encryptedData.length; + if (isOffline()) + rv += 2 + _transientSigningPublicKey.length() + _offlineSignature.length(); + return rv; + } + + // encrypt / decrypt TODO + + @Override + public boolean equals(Object object) { + if (object == this) return true; + if ((object == null) || !(object instanceof EncryptedLeaseSet)) return false; + EncryptedLeaseSet ls = (EncryptedLeaseSet) object; + return + DataHelper.eq(_signature, ls.getSignature()) + && DataHelper.eq(_signingKey, ls.getSigningKey()); + } + + /** the destination has enough randomness in it to use it by itself for speed */ + @Override + public int hashCode() { + if (_encryptionKey == null) + return 0; + return _encryptionKey.hashCode(); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(128); + buf.append("[EncryptedLeaseSet: "); + buf.append("\n\tBlinded Key: ").append(_signingKey); + if (isOffline()) { + buf.append("\n\tTransient Key: ").append(_transientSigningPublicKey); + buf.append("\n\tTransient Expires: ").append(new java.util.Date(_transientExpires)); + buf.append("\n\tOffline Signature: ").append(_offlineSignature); + } + buf.append("\n\tSignature: ").append(_signature); + buf.append("\n\tPublished: ").append(new java.util.Date(_published)); + buf.append("\n\tExpires: ").append(new java.util.Date(_expires)); + buf.append("]"); + return buf.toString(); + } +} diff --git a/core/java/src/net/i2p/data/LeaseSet2.java b/core/java/src/net/i2p/data/LeaseSet2.java index 9ba74b7174..ae832cb717 100644 --- a/core/java/src/net/i2p/data/LeaseSet2.java +++ b/core/java/src/net/i2p/data/LeaseSet2.java @@ -124,6 +124,10 @@ public class LeaseSet2 extends LeaseSet { } public boolean verifyOfflineSignature() { + return verifyOfflineSignature(_destination.getSigningPublicKey()); + } + + protected boolean verifyOfflineSignature(SigningPublicKey spk) { if (!isOffline()) return false; I2PAppContext ctx = I2PAppContext.getGlobalContext(); @@ -276,7 +280,7 @@ public class LeaseSet2 extends LeaseSet { writeOfflineBytes(out); } - private void readOfflineBytes(InputStream in) throws DataFormatException, IOException { + protected void readOfflineBytes(InputStream in) throws DataFormatException, IOException { _transientExpires = DataHelper.readLong(in, 4) * 1000; int itype = (int) DataHelper.readLong(in, 2); SigType type = SigType.getByCode(itype); @@ -289,7 +293,7 @@ public class LeaseSet2 extends LeaseSet { _offlineSignature.readBytes(in); } - private void writeOfflineBytes(OutputStream out) throws DataFormatException, IOException { + protected void writeOfflineBytes(OutputStream out) throws DataFormatException, IOException { if (_transientSigningPublicKey == null || _offlineSignature == null) throw new DataFormatException("No offline key/sig"); DataHelper.writeLong(out, 4, _transientExpires / 1000); diff --git a/core/java/src/net/i2p/data/MetaLeaseSet.java b/core/java/src/net/i2p/data/MetaLeaseSet.java index 66d9e66f2a..eec7dca1f1 100644 --- a/core/java/src/net/i2p/data/MetaLeaseSet.java +++ b/core/java/src/net/i2p/data/MetaLeaseSet.java @@ -1,18 +1,10 @@ package net.i2p.data; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.Properties; -import net.i2p.I2PAppContext; -import net.i2p.crypto.DSAEngine; -import net.i2p.crypto.EncType; -import net.i2p.crypto.SigAlgo; import net.i2p.crypto.SigType; -import net.i2p.util.Clock; -import net.i2p.util.OrderedProperties; /** * PRELIMINARY - Subject to change - see proposal 123 -- GitLab