Compare commits

...

1 Commits

Author SHA1 Message Date
zzz
cfa994cb73 WIP: Compressible padding for RI and Dests
ref: http://zzz.i2p/topics/3279
To be proposal 161

Replaces the 256-byte ElG key in dests with padding.
Make all padding in dests and router identities be a repeating random 32-byte pattern.

This will make gzipped dests and router identities be much smaller:
Dests: appx. 320 bytes smaller (82% reduction)
RIs: appx. 288 bytes smaller (74% reduction)

Expected to primarily benefit database store messages and streaming SYNs.
Does not rekey or affect existing destinations or router identities.
Testers running this patch may be identifiable via transient destinations.
New installs with this patch will be identifiable via router identities.
Tested for several months.
2022-09-17 09:08:59 -04:00
3 changed files with 69 additions and 10 deletions

View File

@@ -41,6 +41,8 @@ import net.i2p.util.RandomSource;
*/
public class I2PClientImpl implements I2PClient {
private static final int PADDING_ENTROPY = 32;
/**
* Create a destination with a DSA 1024/160 signature type and a null certificate.
* This is not bound to the I2PClient, you must supply the data back again
@@ -93,9 +95,23 @@ public class I2PClientImpl implements I2PClient {
*/
public Destination createDestination(OutputStream destKeyStream, Certificate cert) throws I2PException, IOException {
Destination d = new Destination();
Object keypair[] = KeyGenerator.getInstance().generatePKIKeypair();
PublicKey publicKey = (PublicKey) keypair[0];
PrivateKey privateKey = (PrivateKey) keypair[1];
// Don't generate ElGamal keys anymore, they are unused since release 0.6 2005
//Object keypair[] = KeyGenerator.getInstance().generatePKIKeypair();
//PublicKey publicKey = (PublicKey) keypair[0];
//PrivateKey privateKey = (PrivateKey) keypair[1];
// repeating pattern to be used in pubkey and padding, so the
// destination will be compressible
byte[] rand = new byte[PADDING_ENTROPY];
RandomSource.getInstance().nextBytes(rand);
byte[] pk = new byte[PublicKey.KEYSIZE_BYTES];
for (int i = 0; i < pk.length; i += PADDING_ENTROPY) {
System.arraycopy(rand, 0, pk, i, Math.min(PADDING_ENTROPY, pk.length - i));
}
PublicKey publicKey = new PublicKey(pk);
// private key all zeros, just for I2CP
byte[] prk = new byte[PrivateKey.KEYSIZE_BYTES];
PrivateKey privateKey = new PrivateKey(prk);
SimpleDataStructure signingKeys[];
if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
KeyCertificate kcert = cert.toKeyCertificate();
@@ -118,8 +134,12 @@ public class I2PClientImpl implements I2PClient {
SigType type = kcert.getSigType();
int len = type.getPubkeyLen();
if (len < 128) {
byte[] pad = new byte[128 - len];
RandomSource.getInstance().nextBytes(pad);
int padLen = 128 - len;
byte[] pad = new byte[padLen];
// pad with the same pattern as in the public key
for (int i = 0; i < padLen; i += PADDING_ENTROPY) {
System.arraycopy(rand, 0, pad, i, Math.min(PADDING_ENTROPY, padLen - i));
}
d.setPadding(pad);
} else if (len > 128) {
System.arraycopy(signingPubKey.getData(), 128, kcert.getPayload(), KeyCertificate.HEADER_LENGTH, len - 128);

View File

@@ -67,6 +67,13 @@ import net.i2p.util.SecureFileOutputStream;
* Total: 663 or more bytes for ElGamal, may be smaller for other enc. types
*</pre>
*
* Destination encryption keys have been unused since 0.6 (2005).
* As of 0.9.57, new Destination encryption public keys are simply random data.
* Encryption private keys are all zeros.
*
* This class is extended by net.i2p.data.router.RouterPrivateKeyFile.
* RouterIdentity encryption keys ARE used and must be valid.
*
* @author welterde, zzz
*/
@@ -84,6 +91,8 @@ public class PrivateKeyFile {
private SigningPrivateKey _transientSigningPrivKey;
private SigningPublicKey _transientSigningPubKey;
private static final int PADDING_ENTROPY = 32;
/**
* Create a new PrivateKeyFile, or modify an existing one, with various
* types of Certificates.
@@ -591,9 +600,25 @@ public class PrivateKeyFile {
// no support for this in I2PClient,
// so we modify code from CreateRouterInfoJob.createRouterInfo()
I2PAppContext ctx = I2PAppContext.getGlobalContext();
KeyPair keypair = ctx.keyGenerator().generatePKIKeys(ptype);
PublicKey pub = keypair.getPublic();
PrivateKey priv = keypair.getPrivate();
byte[] rand = new byte[PADDING_ENTROPY];
ctx.random().nextBytes(rand);
PublicKey pub;
PrivateKey priv;
if (getClass().equals(PrivateKeyFile.class)) {
// destinations don't use the encryption key
byte[] bpub = new byte[ptype.getPubkeyLen()];
for (int i = 0; i < bpub.length; i += PADDING_ENTROPY) {
System.arraycopy(rand, 0, bpub, i, Math.min(PADDING_ENTROPY, bpub.length - i));
}
pub = new PublicKey(ptype, bpub);
byte[] bpriv = new byte[ptype.getPrivkeyLen()];
priv = new PrivateKey(ptype, bpriv);
} else {
// routers use the encryption key
KeyPair keypair = ctx.keyGenerator().generatePKIKeys(ptype);
pub = keypair.getPublic();
priv = keypair.getPrivate();
}
SimpleDataStructure signingKeypair[] = ctx.keyGenerator().generateSigningKeys(type);
SigningPublicKey spub = (SigningPublicKey)signingKeypair[0];
SigningPrivateKey spriv = (SigningPrivateKey)signingKeypair[1];
@@ -611,7 +636,9 @@ public class PrivateKeyFile {
(PublicKey.KEYSIZE_BYTES - pub.length());
if (padLen > 0) {
padding = new byte[padLen];
ctx.random().nextBytes(padding);
for (int i = 0; i < padLen; i += PADDING_ENTROPY) {
System.arraycopy(rand, 0, padding, i, Math.min(PADDING_ENTROPY, padLen - i));
}
} else {
padding = null;
}
@@ -793,6 +820,8 @@ public class PrivateKeyFile {
}
/**
* Private key may be all zeros for Destinations as of 0.9.57
*
* @return null on error or if not initialized
*/
public PrivateKey getPrivKey() {
@@ -941,6 +970,8 @@ public class PrivateKeyFile {
* Verify that the PublicKey matches the PrivateKey, and
* the SigningPublicKey matches the SigningPrivateKey.
*
* NOTE this will fail for Destinations containing random padding for the enc. key
*
* @return success
* @since 0.9.16
*/

View File

@@ -64,6 +64,7 @@ public class CreateRouterInfoJob extends JobImpl {
private static final EncType DEFAULT_ENCTYPE = (VersionComparator.comp(CoreVersion.VERSION, "0.9.49") >= 0) ?
EncType.ECIES_X25519 :
EncType.ELGAMAL_2048;
private static final int PADDING_ENTROPY = 32;
CreateRouterInfoJob(RouterContext ctx, Job next) {
super(ctx);
@@ -129,7 +130,14 @@ public class CreateRouterInfoJob extends JobImpl {
(PublicKey.KEYSIZE_BYTES - pubkey.length());
if (padLen > 0) {
padding = new byte[padLen];
ctx.random().nextBytes(padding);
if (padLen <= PADDING_ENTROPY) {
ctx.random().nextBytes(padding);
} else {
ctx.random().nextBytes(padding, 0, PADDING_ENTROPY);
for (int i = PADDING_ENTROPY; i < padLen; i += PADDING_ENTROPY) {
System.arraycopy(padding, 0, padding, i, Math.min(PADDING_ENTROPY, padLen - i));
}
}
ident.setPadding(padding);
} else {
padding = null;