Data: Add support for LS2 multiple encryption keys (proposal 123)

This commit is contained in:
zzz
2019-01-01 17:14:37 +00:00
parent 92ad4d1ce3
commit d95d81aea7

View File

@ -4,6 +4,10 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import net.i2p.I2PAppContext;
@ -35,9 +39,12 @@ public class LeaseSet2 extends LeaseSet {
protected Properties _options;
// only used for unknown types; else use _encryptionKey.getType()
private int _encType;
// only used if more than one key, otherwise null
private List<PublicKey> _encryptionKeys;
private static final int FLAG_OFFLINE_KEYS = 1;
private static final int FLAG_UNPUBLISHED = 2;
private static final int MAX_KEYS = 8;
public LeaseSet2() {
super();
@ -59,6 +66,36 @@ public class LeaseSet2 extends LeaseSet {
return _options.getProperty(opt);
}
/**
* Add an encryption key.
*/
public void addEncryptionKey(PublicKey key) {
if (_encryptionKey == null) {
setEncryptionKey(key);
} else {
if (_encryptionKeys == null) {
_encryptionKeys = new ArrayList<PublicKey>(4);
_encryptionKeys.add(_encryptionKey);
} else {
if (_encryptionKeys.size() >= MAX_KEYS)
throw new IllegalStateException();
}
_encryptionKeys.add(key);
}
}
/**
* This returns all the keys. getEncryptionKey() returns the first one.
* @return not a copy, do not modify, null if none
*/
public List<PublicKey> getEncryptionKeys() {
if (_encryptionKeys != null)
return _encryptionKeys;
if (_encryptionKey != null)
return Collections.singletonList(_encryptionKey);
return null;
}
/**
* Configure a set of options or statistics that the router can expose.
* Makes a copy.
@ -193,18 +230,27 @@ public class LeaseSet2 extends LeaseSet {
readHeader(in);
// LS2 part
_options = DataHelper.readProperties(in);
_encType = (int) DataHelper.readLong(in, 2);
int encLen = (int) DataHelper.readLong(in, 2);
// TODO
if (_encType == 0) {
_encryptionKey = PublicKey.create(in);
} else {
EncType type = EncType.getByCode(_encType);
// type will be null if unknown
byte[] encKey = new byte[encLen];
DataHelper.read(in, encKey);
// this will throw IAE if type is non-null and length is wrong
_encryptionKey = new PublicKey(type, encKey);
int numKeys = in.read();
if (numKeys <= 0 || numKeys > MAX_KEYS)
throw new DataFormatException("Bad key count: " + numKeys);
if (numKeys > 1)
_encryptionKeys = new ArrayList<PublicKey>(numKeys);
for (int i = 0; i < numKeys; i++) {
_encType = (int) DataHelper.readLong(in, 2);
int encLen = (int) DataHelper.readLong(in, 2);
// TODO
if (_encType == 0) {
_encryptionKey = PublicKey.create(in);
} else {
EncType type = EncType.getByCode(_encType);
// type will be null if unknown
byte[] encKey = new byte[encLen];
DataHelper.read(in, encKey);
// this will throw IAE if type is non-null and length is wrong
_encryptionKey = new PublicKey(type, encKey);
}
if (numKeys > 1)
_encryptionKeys.add(_encryptionKey);
}
int numLeases = in.read();
if (numLeases > MAX_LEASES)
@ -246,14 +292,18 @@ public class LeaseSet2 extends LeaseSet {
} else {
DataHelper.writeLong(out, 2, 0);
}
EncType type = _encryptionKey.getType();
if (type != null) {
DataHelper.writeLong(out, 2, type.getCode());
} else {
DataHelper.writeLong(out, 2, _encType);
List<PublicKey> keys = getEncryptionKeys();
out.write((byte) keys.size());
for (PublicKey key : keys) {
EncType type = key.getType();
if (type != null) {
DataHelper.writeLong(out, 2, type.getCode());
} else {
DataHelper.writeLong(out, 2, _encType);
}
DataHelper.writeLong(out, 2, key.length());
key.writeBytes(out);
}
DataHelper.writeLong(out, 2, _encryptionKey.length());
_encryptionKey.writeBytes(out);
out.write((byte) _leases.size());
for (Lease lease : _leases) {
lease.writeBytes(out);
@ -433,13 +483,25 @@ public class LeaseSet2 extends LeaseSet {
StringBuilder buf = new StringBuilder(128);
buf.append("[LeaseSet2: ");
buf.append("\n\tDestination: ").append(_destination);
buf.append("\n\tEncryptionKey: ").append(_encryptionKey);
List<PublicKey> keys = getEncryptionKeys();
int sz = keys.size();
buf.append("\n\tEncryption Keys: ").append(sz);
for (int i = 0; i < sz; i++) {
buf.append("\n\tEncryptionKey ").append(i).append(": ").append(keys.get(i));
}
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\tOptions: ").append((_options != null) ? _options.size() : 0);
if (_options != null && !_options.isEmpty()) {
for (Map.Entry<Object, Object> e : _options.entrySet()) {
String key = (String) e.getKey();
String val = (String) e.getValue();
buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
}
}
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));
@ -465,10 +527,10 @@ public class LeaseSet2 extends LeaseSet {
PrivateKeyFile pkf = new PrivateKeyFile(f);
pkf.createIfAbsent(SigType.EdDSA_SHA512_Ed25519);
System.out.println("Online test");
java.io.File f2 = new java.io.File("online-leaseset.dat");
java.io.File f2 = new java.io.File("online-ls2.dat");
test(pkf, f2, false);
System.out.println("Offline test");
f2 = new java.io.File("offline-leaseset.dat");
f2 = new java.io.File("offline-ls2.dat");
test(pkf, f2, true);
}
@ -494,10 +556,13 @@ public class LeaseSet2 extends LeaseSet {
ls2.setDestination(pkf.getDestination());
SimpleDataStructure encKeys[] = net.i2p.crypto.KeyGenerator.getInstance().generatePKIKeys();
PublicKey pubKey = (PublicKey) encKeys[0];
ls2.setEncryptionKey(pubKey);
ls2.addEncryptionKey(pubKey);
net.i2p.crypto.KeyPair encKeys2 = net.i2p.crypto.KeyGenerator.getInstance().generatePKIKeys(net.i2p.crypto.EncType.ECIES_X25519);
pubKey = encKeys2.getPublic();
ls2.addEncryptionKey(pubKey);
SigningPrivateKey spk = pkf.getSigningPrivKey();
if (offline) {
now += 100000;
now += 365*24*60*60*1000L;
SimpleDataStructure transKeys[] = net.i2p.crypto.KeyGenerator.getInstance().generateSigningKeys(SigType.EdDSA_SHA512_Ed25519);
SigningPublicKey transientPub = (SigningPublicKey) transKeys[0];
SigningPrivateKey transientPriv = (SigningPrivateKey) transKeys[1];