From 91bcf947df16df1b4b017fcd616bf9060440a3cc Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 30 Aug 2010 17:51:49 +0000 Subject: [PATCH 1/3] * Javadocs * Base64: comment out some unused methods * Remove huge whitespace in CryptoConstants * ElGamalAESEngine: - Reduce rates - Check number of tags earlier --- .../i2p/i2ptunnel/I2PTunnelConnectClient.java | 4 ++ .../net/i2p/i2ptunnel/I2PTunnelRunner.java | 2 + .../streaming/I2PSocketManagerFull.java | 13 +++- .../src/net/i2p/crypto/CryptixAESEngine.java | 4 +- .../src/net/i2p/crypto/CryptoConstants.java | 14 ++--- .../src/net/i2p/crypto/ElGamalAESEngine.java | 48 +++++++++++--- .../src/net/i2p/crypto/ElGamalEngine.java | 19 +++++- core/java/src/net/i2p/data/Base32.java | 22 +++++-- core/java/src/net/i2p/data/Base64.java | 41 ++++++++++-- .../net/i2p/data/i2np/BuildRequestRecord.java | 4 +- .../router/message/GarlicMessageBuilder.java | 5 ++ .../networkdb/kademlia/MessageWrapper.java | 2 +- .../router/transport/ntcp/EstablishState.java | 62 +++++++++++++++---- .../router/transport/udp/PacketBuilder.java | 1 + 14 files changed, 193 insertions(+), 48 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java index 7a80c181f6..fe92e94b6f 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java @@ -26,6 +26,7 @@ import net.i2p.util.Log; /** * Supports the following: + *
  *   (where protocol is generally HTTP/1.1 but is ignored)
  *   (where host is one of:
  *      example.i2p
@@ -39,16 +40,19 @@ import net.i2p.util.Log;
  *   CONNECT host protocol
  *   CONNECT host:port
  *   CONNECT host:port protocol (this is the standard)
+ *
* * Additional lines after the CONNECT line but before the blank line are ignored and stripped. * The CONNECT line is removed for .i2p accesses * but passed along for outproxy accesses. * * Ref: + *
  *  INTERNET-DRAFT                                              Ari Luotonen
  *  Expires: September 26, 1997          Netscape Communications Corporation
  *                       March 26, 1997
  *                     Tunneling SSL Through a WWW Proxy
+ *
* * @author zzz a stripped-down I2PTunnelHTTPClient */ diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java index 6be20ba8bb..c2a014020d 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java @@ -127,6 +127,8 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr // this does not increment totalSent i2pout.write(initialI2PData); // do NOT flush here, it will block and then onTimeout.run() won't happen on fail. + // But if we don't flush, then we have to wait for the connectDelay timer to fire + // in i2p socket? To be researched and/or fixed. //i2pout.flush(); } } diff --git a/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketManagerFull.java b/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketManagerFull.java index b904243b10..c26a27fe26 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketManagerFull.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/I2PSocketManagerFull.java @@ -176,7 +176,11 @@ public class I2PSocketManagerFull implements I2PSocketManager { } /** - * Create a new connected socket (block until the socket is created) + * Create a new connected socket. Blocks until the socket is created, + * unless the connectDelay option (i2p.streaming.connectDelay) is + * set and greater than zero. If so this will return immediately, + * and the client may quickly write initial data to the socket and + * this data will be bundled in the SYN packet. * * @param peer Destination to connect to * @param options I2P socket options to be used for connecting @@ -199,6 +203,7 @@ public class I2PSocketManagerFull implements I2PSocketManager { if (_log.shouldLog(Log.INFO)) _log.info("Connecting to " + peer.calculateHash().toBase64().substring(0,6) + " with options: " + opts); + // the following blocks unless connect delay > 0 Connection con = _connectionManager.connect(peer, opts); if (con == null) throw new TooManyStreamsException("Too many streams (max " + _maxStreams + ")"); @@ -212,7 +217,11 @@ public class I2PSocketManagerFull implements I2PSocketManager { } /** - * Create a new connected socket (block until the socket is created) + * Create a new connected socket. Blocks until the socket is created, + * unless the connectDelay option (i2p.streaming.connectDelay) is + * set and greater than zero in the default options. If so this will return immediately, + * and the client may quickly write initial data to the socket and + * this data will be bundled in the SYN packet. * * @param peer Destination to connect to * diff --git a/core/java/src/net/i2p/crypto/CryptixAESEngine.java b/core/java/src/net/i2p/crypto/CryptixAESEngine.java index fb3393dcdb..acd2eb702a 100644 --- a/core/java/src/net/i2p/crypto/CryptixAESEngine.java +++ b/core/java/src/net/i2p/crypto/CryptixAESEngine.java @@ -41,11 +41,13 @@ public class CryptixAESEngine extends AESEngine { _cache = new CryptixAESKeyCache(); } + /** @param length must be a multiple of 16 */ @Override public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) { encrypt(payload, payloadIndex, out, outIndex, sessionKey, iv, 0, length); } + /** @param length must be a multiple of 16 */ @Override public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int ivOffset, int length) { if ( (payload == null) || (out == null) || (sessionKey == null) || (iv == null) ) @@ -142,7 +144,7 @@ public class CryptixAESEngine extends AESEngine { CryptixRijndael_Algorithm.blockEncrypt(payload, out, inIndex, outIndex, sessionKey.getPreparedKey(), 16); } - /** decrypt the data with the session key provided + /** decrypt exactly 16 bytes of data with the session key provided * @param payload encrypted data * @param sessionKey private session key */ diff --git a/core/java/src/net/i2p/crypto/CryptoConstants.java b/core/java/src/net/i2p/crypto/CryptoConstants.java index 4728de8de7..228a92e849 100644 --- a/core/java/src/net/i2p/crypto/CryptoConstants.java +++ b/core/java/src/net/i2p/crypto/CryptoConstants.java @@ -35,21 +35,21 @@ import net.i2p.util.NativeBigInteger; /** * Prime for ElGamal from http://tools.ietf.org/html/rfc3526 - * Primes for DSA: unknown. + * Primes for DSA: Generated by TheCrypto http://article.gmane.org/gmane.comp.security.invisiblenet.iip.devel/343 */ public class CryptoConstants { public static final BigInteger dsap = new NativeBigInteger( "9c05b2aa960d9b97b8931963c9cc9e8c3026e9b8ed92fad0a69cc886d5bf8015fcadae31" - + "a0ad18fab3f01b00a358de237655c4964afaa2b337e96ad316b9fb1cc564b5aec5b69a9f" - + "f6c3e4548707fef8503d91dd8602e867e6d35d2235c1869ce2479c3b9d5401de04e0727f" - + "b33d6511285d4cf29538d9e3b6051f5b22cc1c93", + + "a0ad18fab3f01b00a358de237655c4964afaa2b337e96ad316b9fb1cc564b5aec5b69a9f" + + "f6c3e4548707fef8503d91dd8602e867e6d35d2235c1869ce2479c3b9d5401de04e0727f" + + "b33d6511285d4cf29538d9e3b6051f5b22cc1c93", 16); public static final BigInteger dsaq = new NativeBigInteger("a5dfc28fef4ca1e286744cd8eed9d29d684046b7", 16); public static final BigInteger dsag = new NativeBigInteger( "c1f4d27d40093b429e962d7223824e0bbc47e7c832a39236fc683af84889581075ff9082" - + "ed32353d4374d7301cda1d23c431f4698599dda02451824ff369752593647cc3ddc197de" - + "985e43d136cdcfc6bd5409cd2f450821142a5e6f8eb1c3ab5d0484b8129fcf17bce4f7f3" - + "3321c3cb3dbb14a905e7b2b3e93be4708cbcc82", + + "ed32353d4374d7301cda1d23c431f4698599dda02451824ff369752593647cc3ddc197de" + + "985e43d136cdcfc6bd5409cd2f450821142a5e6f8eb1c3ab5d0484b8129fcf17bce4f7f3" + + "3321c3cb3dbb14a905e7b2b3e93be4708cbcc82", 16); public static final BigInteger elgp = new NativeBigInteger("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" diff --git a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java index 820a57c672..f4f276de22 100644 --- a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java +++ b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java @@ -43,19 +43,19 @@ public class ElGamalAESEngine { _context.statManager().createFrequencyStat("crypto.elGamalAES.encryptNewSession", "how frequently we encrypt to a new ElGamal/AES+SessionTag session?", - "Encryption", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l}); + "Encryption", new long[] { 60*60*1000l}); _context.statManager().createFrequencyStat("crypto.elGamalAES.encryptExistingSession", "how frequently we encrypt to an existing ElGamal/AES+SessionTag session?", - "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); + "Encryption", new long[] { 60*60*1000l}); _context.statManager().createFrequencyStat("crypto.elGamalAES.decryptNewSession", "how frequently we decrypt with a new ElGamal/AES+SessionTag session?", - "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); + "Encryption", new long[] { 60*60*1000l}); _context.statManager().createFrequencyStat("crypto.elGamalAES.decryptExistingSession", "how frequently we decrypt with an existing ElGamal/AES+SessionTag session?", - "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); + "Encryption", new long[] { 60*60*1000l}); _context.statManager().createFrequencyStat("crypto.elGamalAES.decryptFailed", - "how frequently we fail to decrypt with ElGamal/AES+SessionTag?", "Encryption", - new long[] { 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); + "how frequently we fail to decrypt with ElGamal/AES+SessionTag?", + "Encryption", new long[] { 60*60*1000l}); } /** @@ -73,6 +73,7 @@ public class ElGamalAESEngine { * This works according to the * ElGamal+AES algorithm in the data structure spec. * + * @return decrypted data or null on failure */ public byte[] decrypt(byte data[], PrivateKey targetPrivateKey, SessionKeyManager keyManager) throws DataFormatException { if (data == null) { @@ -148,9 +149,12 @@ public class ElGamalAESEngine { /** * scenario 1: * Begin with 222 bytes, ElG encrypted, containing: + *
      *  - 32 byte SessionKey
      *  - 32 byte pre-IV for the AES
      *  - 158 bytes of random padding
+     * 
+ * After encryption, the ElG section is 514 bytes long. * Then encrypt with AES using that session key and the first 16 bytes of the SHA256 of the pre-IV, using * the decryptAESBlock method & structure. * @@ -213,6 +217,7 @@ public class ElGamalAESEngine { * scenario 2: * The data begins with 32 byte session tag, which also serves as the preIV. * Then decrypt with AES using that session key and the first 16 bytes of the SHA256 of the pre-IV: + *
      *  - 2 byte integer specifying the # of session tags
      *  - that many 32 byte session tags
      *  - 4 byte integer specifying data.length
@@ -220,11 +225,13 @@ public class ElGamalAESEngine {
      *  - 1 byte flag that, if == 1, is followed by a new SessionKey
      *  - data
      *  - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0
+     * 
* * If anything doesn't match up in decryption, it falls back to decryptNewSession * * @param foundTags set which is filled with any sessionTags found during decryption * @param foundKey session key which may be filled with a new sessionKey found during decryption + * @return decrypted data or null on failure * */ byte[] decryptExistingSession(byte data[], SessionKey key, PrivateKey targetPrivateKey, Set foundTags, @@ -264,6 +271,7 @@ public class ElGamalAESEngine { /** * Decrypt the AES data with the session key and IV. The result should be: + *
      *  - 2 byte integer specifying the # of session tags
      *  - that many 32 byte session tags
      *  - 4 byte integer specifying data.length
@@ -271,6 +279,7 @@ public class ElGamalAESEngine {
      *  - 1 byte flag that, if == 1, is followed by a new SessionKey
      *  - data
      *  - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0
+     * 
* * If anything doesn't match up in decryption, return null. Otherwise, return * the decrypted data and update the session as necessary. If the sentTag is not null, @@ -278,6 +287,7 @@ public class ElGamalAESEngine { * * @param foundTags set which is filled with any sessionTags found during decryption * @param foundKey session key which may be filled with a new sessionKey found during decryption + * @return decrypted data or null on failure */ byte[] decryptAESBlock(byte encrypted[], SessionKey key, byte iv[], byte sentTag[], Set foundTags, SessionKey foundKey) throws DataFormatException { @@ -299,10 +309,10 @@ public class ElGamalAESEngine { //ByteArrayInputStream bais = new ByteArrayInputStream(decrypted); int cur = 0; long numTags = DataHelper.fromLong(decrypted, cur, 2); + if ((numTags < 0) || (numTags > 200)) throw new Exception("Invalid number of session tags"); if (numTags > 0) tags = new ArrayList((int)numTags); cur += 2; //_log.debug("# tags: " + numTags); - if ((numTags < 0) || (numTags > 200)) throw new Exception("Invalid number of session tags"); if (numTags * SessionTag.BYTE_LENGTH > decrypted.length - 2) { throw new Exception("# tags: " + numTags + " is too many for " + (decrypted.length - 2)); } @@ -363,6 +373,8 @@ public class ElGamalAESEngine { * @param newKey key to be delivered to the target, with which the tagsForDelivery should be associated, or null * @param paddedSize minimum size in bytes of the body after padding it (if less than the * body's real size, no bytes are appended but the body is not truncated) + * + * Unused externally, only called by below (i.e. newKey is always null) */ public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, SessionTag currentTag, SessionKey newKey, long paddedSize) { @@ -384,6 +396,7 @@ public class ElGamalAESEngine { /** * Encrypt the data to the target using the given key and deliver the specified tags * No new session key + * This is the one called from GarlicMessageBuilder and is the primary entry point. */ public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, SessionTag currentTag, long paddedSize) { @@ -394,6 +407,8 @@ public class ElGamalAESEngine { * Encrypt the data to the target using the given key and deliver the specified tags * No new session key * No current tag (encrypt as new session) + * + * @deprecated unused */ public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, long paddedSize) { return encrypt(data, target, key, tagsForDelivery, null, null, paddedSize); @@ -403,6 +418,8 @@ public class ElGamalAESEngine { * Encrypt the data to the target using the given key delivering no tags * No new session key * No current tag (encrypt as new session) + * + * @deprecated unused */ public byte[] encrypt(byte data[], PublicKey target, SessionKey key, long paddedSize) { return encrypt(data, target, key, null, null, null, paddedSize); @@ -411,10 +428,14 @@ public class ElGamalAESEngine { /** * scenario 1: * Begin with 222 bytes, ElG encrypted, containing: + *
      *  - 32 byte SessionKey
      *  - 32 byte pre-IV for the AES
      *  - 158 bytes of random padding
-     * Then encrypt with AES using that session key and the first 16 bytes of the SHA256 of the pre-IV:
+     * 
+ * After encryption, the ElG section is 514 bytes long. + * Then encrypt the following with AES using that session key and the first 16 bytes of the SHA256 of the pre-IV: + *
      *  - 2 byte integer specifying the # of session tags
      *  - that many 32 byte session tags
      *  - 4 byte integer specifying data.length
@@ -422,6 +443,7 @@ public class ElGamalAESEngine {
      *  - 1 byte flag that, if == 1, is followed by a new SessionKey
      *  - data
      *  - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0
+     * 
* */ byte[] encryptNewSession(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, @@ -440,10 +462,12 @@ public class ElGamalAESEngine { //_log.debug("SessionKey for encryptNewSession: " + DataHelper.toString(key.getData(), 32)); long before = _context.clock().now(); byte elgEncr[] = _context.elGamalEngine().encrypt(elgSrcData, target); - long after = _context.clock().now(); - if (_log.shouldLog(Log.INFO)) + if (_log.shouldLog(Log.INFO)) { + long after = _context.clock().now(); _log.info("elgEngine.encrypt of the session key took " + (after - before) + "ms"); + } if (elgEncr.length < 514) { + // ??? ElGamalEngine.encrypt() always returns 514 bytes byte elg[] = new byte[514]; int diff = elg.length - elgEncr.length; //if (_log.shouldLog(Log.DEBUG)) _log.debug("Difference in size: " + diff); @@ -474,6 +498,7 @@ public class ElGamalAESEngine { * scenario 2: * Begin with 32 byte session tag, which also serves as the preIV. * Then encrypt with AES using that session key and the first 16 bytes of the SHA256 of the pre-IV: + *
      *  - 2 byte integer specifying the # of session tags
      *  - that many 32 byte session tags
      *  - 4 byte integer specifying data.length
@@ -481,6 +506,7 @@ public class ElGamalAESEngine {
      *  - 1 byte flag that, if == 1, is followed by a new SessionKey
      *  - data
      *  - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0
+     * 
* */ byte[] encryptExistingSession(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, @@ -506,6 +532,7 @@ public class ElGamalAESEngine { * For both scenarios, this method encrypts the AES area using the given key, iv * and making sure the resulting data is at least as long as the paddedSize and * also mod 16 bytes. The contents of the encrypted data is: + *
      *  - 2 byte integer specifying the # of session tags
      *  - that many 32 byte session tags
      *  - 4 byte integer specifying data.length
@@ -513,6 +540,7 @@ public class ElGamalAESEngine {
      *  - 1 byte flag that, if == 1, is followed by a new SessionKey
      *  - data
      *  - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0
+     * 
* */ final byte[] encryptAESBlock(byte data[], SessionKey key, byte[] iv, Set tagsForDelivery, SessionKey newKey, diff --git a/core/java/src/net/i2p/crypto/ElGamalEngine.java b/core/java/src/net/i2p/crypto/ElGamalEngine.java index c5e9cd963d..ae3b0eb3ad 100644 --- a/core/java/src/net/i2p/crypto/ElGamalEngine.java +++ b/core/java/src/net/i2p/crypto/ElGamalEngine.java @@ -85,9 +85,17 @@ public class ElGamalEngine { } /** encrypt the data to the public key - * @return encrypted data, will be about twice as big as the cleartext + * @return encrypted data, will be exactly 514 bytes long + * Contains the two-part encrypted data starting at bytes 0 and 257. + * If the encrypted parts are smaller than 257 bytes, they will be + * padded with leading zeros. + * The parts appear to always be 256 bytes or less, in other words, + * bytes 0 and 257 are always zero. * @param publicKey public key encrypt to * @param data data to encrypt, must be 222 bytes or less + * As the encrypted data may contain a substantial number of zeros if the + * cleartext is smaller than 222 bytes, it is recommended that the caller pad + * the cleartext to 222 bytes with random data. */ public byte[] encrypt(byte data[], PublicKey publicKey) { if ((data == null) || (data.length >= 223)) @@ -97,6 +105,7 @@ public class ElGamalEngine { long start = _context.clock().now(); byte d2[] = new byte[1+Hash.HASH_LENGTH+data.length]; + // FIXME this isn't a random nonzero byte! d2[0] = (byte)0xFF; Hash hash = _context.sha().calculateHash(data); System.arraycopy(hash.getData(), 0, d2, 1, Hash.HASH_LENGTH); @@ -156,11 +165,15 @@ public class ElGamalEngine { } /** Decrypt the data - * @param encrypted encrypted data, must be 514 bytes or less + * @param encrypted encrypted data, must be exactly 514 bytes + * Contains the two-part encrypted data starting at bytes 0 and 257. + * If the encrypted parts are smaller than 257 bytes, they must be + * padded with leading zeros. * @param privateKey private key to decrypt with - * @return unencrypted data + * @return unencrypted data or null on failure */ public byte[] decrypt(byte encrypted[], PrivateKey privateKey) { + // actually it must be exactly 514 bytes or the arraycopy below will AIOOBE if ((encrypted == null) || (encrypted.length > 514)) throw new IllegalArgumentException("Data to decrypt must be <= 514 bytes at the moment"); long start = _context.clock().now(); diff --git a/core/java/src/net/i2p/data/Base32.java b/core/java/src/net/i2p/data/Base32.java index adb7e9196c..3071e0bc01 100644 --- a/core/java/src/net/i2p/data/Base32.java +++ b/core/java/src/net/i2p/data/Base32.java @@ -23,12 +23,14 @@ import net.i2p.util.Log; * No whitespace allowed. * * Decode accepts upper or lower case. + * @author zzz + * @since 0.7 */ public class Base32 { private final static Log _log = new Log(Base32.class); - /** The 64 valid Base32 values. */ + /** The 32 valid Base32 values. */ private final static char[] ALPHABET = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', @@ -132,10 +134,16 @@ public class Base32 { System.out.println("or : Base32 decode"); } + /** + * @param source if null will return "" + */ public static String encode(String source) { return (source != null ? encode(source.getBytes()) : ""); } + /** + * @param source The data to convert non-null + */ public static String encode(byte[] source) { StringBuilder buf = new StringBuilder((source.length + 7) * 8 / 5); encodeBytes(source, buf); @@ -147,7 +155,7 @@ public class Base32 { /** * Encodes a byte array into Base32 notation. * - * @param source The data to convert + * @param source The data to convert non-null */ private static void encodeBytes(byte[] source, StringBuilder out) { int usedbits = 0; @@ -174,7 +182,7 @@ public class Base32 { * Decodes data from Base32 notation and * returns it as a string. * - * @param s the string to decode + * @param s the string to decode, if null returns null * @return The data as a string or null on failure */ public static String decodeToString(String s) { @@ -184,6 +192,10 @@ public class Base32 { return new String(b); } + /** + * @param s non-null + * @return decoded data, null on error + */ public static byte[] decode(String s) { return decode(s.getBytes()); } @@ -194,8 +206,8 @@ public class Base32 { * Decodes Base32 content in byte array format and returns * the decoded byte array. * - * @param source The Base32 encoded data - * @return decoded data + * @param source The Base32 encoded data non-null + * @return decoded data, null on error */ private static byte[] decode(byte[] source) { int len58; diff --git a/core/java/src/net/i2p/data/Base64.java b/core/java/src/net/i2p/data/Base64.java index 2b9fe85e6f..b5e03b03c7 100644 --- a/core/java/src/net/i2p/data/Base64.java +++ b/core/java/src/net/i2p/data/Base64.java @@ -42,23 +42,46 @@ public class Base64 { private final static Log _log = new Log(Base64.class); - /** added by aum */ + /** + * @param source if null will return "" + */ public static String encode(String source) { return (source != null ? encode(source.getBytes()) : ""); } + + /** + * @param source if null will return "" + */ public static String encode(byte[] source) { return (source != null ? encode(source, 0, source.length) : ""); } + + /** + * @param source if null will return "" + */ public static String encode(byte[] source, int off, int len) { return (source != null ? encode(source, off, len, false) : ""); } + + /** + * @param source if null will return "" + * @param useStandardAlphabet Warning, must be false for I2P compatibility + */ public static String encode(byte[] source, boolean useStandardAlphabet) { return (source != null ? encode(source, 0, source.length, useStandardAlphabet) : ""); } + + /** + * @param source if null will return "" + * @param useStandardAlphabet Warning, must be false for I2P compatibility + */ public static String encode(byte[] source, int off, int len, boolean useStandardAlphabet) { return (source != null ? safeEncode(source, off, len, useStandardAlphabet) : ""); } + /** + * @param s Base 64 encoded string using the I2P alphabet A-Z, a-z, 0-9, -, ~ + */ public static byte[] decode(String s) { return safeDecode(s, false); } @@ -84,6 +107,8 @@ public class Base64 { (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/'}; + + /** The 64 valid Base64 values for I2P. */ private final static byte[] ALPHABET_ALT = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', @@ -241,7 +266,7 @@ public class Base64 { * @return four byte array in Base64 notation. * @since 1.3 */ -/***** unused +/***** unused (standard alphabet) private static byte[] encode3to4(byte[] threeBytes) { return encode3to4(threeBytes, 3); } // end encodeToBytes @@ -260,11 +285,13 @@ public class Base64 { * @return four byte array in Base64 notation. * @since 1.3 */ +/***** unused (standard alphabet) private static byte[] encode3to4(byte[] threeBytes, int numSigBytes) { byte[] dest = new byte[4]; encode3to4(threeBytes, 0, numSigBytes, dest, 0); return dest; } +******/ /** * Encodes up to three bytes of the array source @@ -287,6 +314,7 @@ public class Base64 { * @return the destination array * @since 1.3 */ +/***** unused (standard alphabet) private static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset) { // 1 2 3 // 01234567890123456789012345678901 Bit position @@ -329,7 +357,11 @@ public class Base64 { return destination; } // end switch } // end encode3to4 +******/ + /** + * @param alpha alphabet + */ private static void encode3to4(byte[] source, int srcOffset, int numSigBytes, StringBuilder buf, byte alpha[]) { // 1 2 3 // 01234567890123456789012345678901 Bit position @@ -628,7 +660,7 @@ public class Base64 { * Decodes data from Base64 notation. * * @param s the string to decode - * @return the decoded data + * @return the decoded data, null on error * @since 1.4 */ private static byte[] standardDecode(String s) { @@ -647,6 +679,7 @@ public class Base64 { * @param s the strind to decode * @return The data as a string * @since 1.4 + * @throws NPE on error? */ public static String decodeToString(String s) { return new String(decode(s)); @@ -659,7 +692,7 @@ public class Base64 { * @param source The Base64 encoded data * @param off The offset of where to begin decoding * @param len The length of characters to decode - * @return decoded data + * @return decoded data, null on error * @since 1.3 */ private static byte[] decode(byte[] source, int off, int len) { diff --git a/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java b/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java index 7bd8352b65..7ff81a2add 100644 --- a/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java +++ b/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java @@ -23,7 +23,7 @@ import net.i2p.data.SessionKey; * byte 184: flags * bytes 185-188: request time (in hours since the epoch) * bytes 189-192: next message ID - * bytes 193-222: uninterpreted / random padding + * bytes 193-221: uninterpreted / random padding * * */ @@ -226,7 +226,7 @@ public class BuildRequestRecord { * byte 184: flags * bytes 185-188: request time (in hours since the epoch) * bytes 189-192: next message ID - * bytes 193-222: uninterpreted / random padding + * bytes 193-221: uninterpreted / random padding */ DataHelper.toLong(buf, OFF_RECV_TUNNEL, 4, receiveTunnelId); System.arraycopy(peer.getData(), 0, buf, OFF_OUR_IDENT, Hash.HASH_LENGTH); diff --git a/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java b/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java index a9bea9c2fb..99c282a0cb 100644 --- a/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java +++ b/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java @@ -35,6 +35,7 @@ public class GarlicMessageBuilder { /** * This was 100 since 0.6.1.10 (50 before that). It's important because: + *
      *  - Tags are 32 bytes. So it previously added 3200 bytes to an initial message.
      *  - Too many tags adds a huge overhead to short-duration connections
      *    (like http, datagrams, etc.)
@@ -43,14 +44,17 @@ public class GarlicMessageBuilder {
      *  - This reduces the effective maximum datagram size because the client
      *    doesn't know when tags will be bundled, so the tag size must be
      *    subtracted from the maximum I2NP size or transport limit.
+     * 
* * Issues with too small a value: + *
      *  - When tags are sent, a reply leaseset (~1KB) is always bundled.
      *    Maybe don't need to bundle more than every minute or so
      *    rather than every time?
      *  - Does the number of tags (and the threshold of 20) limit the effective
      *    streaming lib window size? Should the threshold and the number of
      *    sent tags be variable based on the message rate?
+     * 
* * We have to be very careful if we implement an adaptive scheme, * since the key manager is per-router, not per-local-dest. @@ -218,6 +222,7 @@ public class GarlicMessageBuilder { byte cloveSet[] = buildCloveSet(ctx, config); + // TODO - 128 is the minimum padded size - should it be more? less? random? byte encData[] = ctx.elGamalAESEngine().encrypt(cloveSet, target, encryptKey, wrappedTags, encryptTag, 128); msg.setData(encData); msg.setMessageExpiration(config.getExpiration()); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java b/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java index 82c7f121f0..1f521455e5 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java @@ -20,7 +20,7 @@ import net.i2p.router.message.PayloadGarlicConfig; import net.i2p.util.Log; /** - * Method an class for garlic encrypting outbound netdb traffic, + * Method and class for garlic encrypting outbound netdb traffic, * including management of the ElGamal/AES tags * * @since 0.7.10 diff --git a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java index 747c923ece..dce7d0de71 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java +++ b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java @@ -29,18 +29,45 @@ import net.i2p.router.Router; import net.i2p.router.RouterContext; import net.i2p.util.Log; -/* +/** + * Handle the 4-phase establishment, which is as follows: + * + *
+ *
  * Alice                   contacts                      Bob
  * =========================================================
+ *
+ * Message 1 (Session Request):
  *  X+(H(X) xor Bob.identHash)----------------------------->
+ *
+ * Message 2 (Session Created):
  *  <----------------------------------------Y+E(H(X+Y)+tsB, sk, Y[239:255])
- *  E(#+Alice.identity+tsA+padding+S(X+Y+Bob.identHash+tsA+tsB+padding), sk, hX_xor_Bob.identHash[16:31])--->
+ *
+ * Message 3 (Session Confirm A):
+ *  E(sz+Alice.identity+tsA+padding+S(X+Y+Bob.identHash+tsA+tsB), sk, hX_xor_Bob.identHash[16:31])--->
+ *
+ * Message 4 (Session Confirm B):
  *  <----------------------E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev)
  *
+ *  Key:
+ *
+ *    X, Y: 256 byte DH keys
+ *    H(): 32 byte SHA256 Hash
+ *    E(data, session key, IV): AES256 Encrypt
+ *    S(): 40 byte DSA Signature
+ *    tsA, tsB: timestamps (4 bytes, seconds since epoch)
+ *    sk: 32 byte Session key
+ *    sz: 2 byte size of Alice identity to follow
+ *
+ * 
+ * + * * Alternately, when Bob receives a connection, it could be a * check connection (perhaps prompted by Bob asking for someone * to verify his listener). check connections are formatted per - * {@link #isCheckInfo()} + * isCheckInfo() + * NOTE: Check info is unused. + * */ public class EstablishState { private RouterContext _context; @@ -57,7 +84,9 @@ public class EstablishState { // alice receives (and bob sends) private byte _Y[]; private transient byte _e_hXY_tsB[]; + /** Bob's Timestamp in seconds */ private transient long _tsB; + /** Alice's Timestamp in seconds */ private transient long _tsA; private transient byte _e_bobSig[]; @@ -98,9 +127,6 @@ public class EstablishState { _log = ctx.logManager().getLog(getClass()); _transport = transport; _con = con; - _verified = false; - _corrupt = false; - _confirmWritten = false; _dh = new DHSessionKeyBuilder(); if (_con.isInbound()) { _X = new byte[256]; @@ -116,10 +142,7 @@ public class EstablishState { _prevEncrypted = new byte[16]; _curEncrypted = new byte[16]; - _curEncryptedOffset = 0; _curDecrypted = new byte[16]; - - _received = 0; } /** @@ -150,7 +173,10 @@ public class EstablishState { public boolean getFailedBySkew() { return _failedBySkew; } - /** we are Bob, so receive these bytes as part of an inbound connection */ + /** + * we are Bob, so receive these bytes as part of an inbound connection + * This method receives messages 1 and 3, and sends messages 2 and 4. + */ private void receiveInbound(ByteBuffer src) { if (_log.shouldLog(Log.DEBUG)) _log.debug(prefix()+"Receiving inbound: prev received=" + _received + " src.remaining=" + src.remaining()); @@ -311,7 +337,10 @@ public class EstablishState { } } - /** we are Alice, so receive these bytes as part of an outbound connection */ + /** + * We are Alice, so receive these bytes as part of an outbound connection. + * This method receives messages 2 and 4, and sends message 3. + */ private void receiveOutbound(ByteBuffer src) { if (_log.shouldLog(Log.DEBUG)) _log.debug(prefix()+"Receive outbound " + src + " received=" + _received); @@ -498,8 +527,10 @@ public class EstablishState { public boolean isComplete() { return _verified; } /** - * we are establishing an outbound connection, so prepare ourselves by + * We are Alice. + * We are establishing an outbound connection, so prepare ourselves by * queueing up the write of the first part of the handshake + * This method sends message #1 to Bob. */ public void prepareOutbound() { if (_received <= 0) { @@ -516,7 +547,9 @@ public class EstablishState { } /** - * make sure the signatures are correct, and if they are, update the + * We are Bob. Verify message #3 from Alice, then send message #4 to Alice. + * + * Make sure the signatures are correct, and if they are, update the * NIOConnection with the session key / peer ident / clock skew / iv. * The NIOConnection itself is responsible for registering with the * transport @@ -623,6 +656,9 @@ public class EstablishState { } } + /** + * We are Bob. Send message #4 to Alice. + */ private void sendInboundConfirm(RouterIdentity alice, long tsA) { // send Alice E(S(X+Y+Alice.identHash+tsA+tsB), sk, prev) byte toSign[] = new byte[256+256+32+4+4]; diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java index c0d9e22f3f..3ebbdd3438 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -607,6 +607,7 @@ public class PacketBuilder { // pad here if we want. maybe randomized? // pad up so we're on the encryption boundary + // TODO: why not random data? if ( (off % 16) != 0) off += 16 - (off % 16); packet.getPacket().setLength(off); From db0bc1a6183c257fde546452a10b8197f7cf604c Mon Sep 17 00:00:00 2001 From: forget Date: Tue, 7 Sep 2010 03:24:28 +0000 Subject: [PATCH 2/3] Fixed: missing links to the new Swedish help page. --- installer/resources/eepsite.help/help/index_nl.html | 2 +- installer/resources/eepsite.help/help/index_ru.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/installer/resources/eepsite.help/help/index_nl.html b/installer/resources/eepsite.help/help/index_nl.html index 5d6c9a61ac..290b1718fa 100644 --- a/installer/resources/eepsite.help/help/index_nl.html +++ b/installer/resources/eepsite.help/help/index_nl.html @@ -17,7 +17,7 @@ Français Nederlands Русский -Svenska +Svenska

Korte Handleiding voor Anoniem Webhosten op I2P

diff --git a/installer/resources/eepsite.help/help/index_ru.html b/installer/resources/eepsite.help/help/index_ru.html index 9c8eccdc3d..2c6c0e2ffd 100644 --- a/installer/resources/eepsite.help/help/index_ru.html +++ b/installer/resources/eepsite.help/help/index_ru.html @@ -17,7 +17,7 @@ Français Nederlands Русский -Svenska +Svenska

Краткое руководство по анонимному хостингу сайтов в I2P

From 73d956462f5ff150bb388912bd9da211e3cbd89c Mon Sep 17 00:00:00 2001 From: forget Date: Tue, 7 Sep 2010 03:25:48 +0000 Subject: [PATCH 3/3] Fixed: recoded to UTF-8, cyrillic and chinese labels repaired. --- .../resources/eepsite.help/help/index_sv.html | 272 +++++++++--------- 1 file changed, 136 insertions(+), 136 deletions(-) diff --git a/installer/resources/eepsite.help/help/index_sv.html b/installer/resources/eepsite.help/help/index_sv.html index c044bd2716..1eb42e9290 100644 --- a/installer/resources/eepsite.help/help/index_sv.html +++ b/installer/resources/eepsite.help/help/index_sv.html @@ -1,137 +1,137 @@ - - - I2P Anonym Webbserver | Vlkommen till din eepsite - - - - - -
-
-

I2P Anonym Webbserver

-
- -English -?? -Deutsch -Franais -Nederlands -??????? -Svenska - -
-

Snabb vgledning till anonym webbservning p I2P

- -

Det hr r din eepsite, din egen anonyma I2P-webbserver - redigera bara filerna - under ~/.i2p/eepsite/docroot/ (Linux, OS X) - eller %APPDATA%\I2P\eepsite\docroot\ (Windows) - s kommer andra kunna n dem efter att du fljt instruktionerna nedan. - I I2P s adresseras eepsajter med en 'nyckel', som representeras som en vldigt lng Base64-strng. - ('Nyckeln' r ngot s nr analog med en IP-adress och visas - p eepsajtens I2PTunnel-konfigurationssida). - Nedan ges instruktioner om hur du kan ange ett namn som "minsajt.i2p" till din nyckel och brja kra din eepsajt.

-

Du kan n din eepsajt lokalt via - http://127.0.0.1:7658/. -

- -

Att stta upp och annonsera din eepsajt

- Din eepsajt r stoppad som standard. - Efter att du startat den kommer det att vara svrt fr att andra att hitta den, - eftersom den inte har ett namn och de inte knner till din mycket lnga Base64-nyckel. - Du skulle bara kunna bertta fr andra om den lnga nyckeln, men tacksamt nog har i2p en - adressbok och mnga enkla stt att bertta fr folk om din eepsajt. Hr r alla stegen. -
    -
  • Vlj ett namn t din eepsajt (ettbranamn.i2p). Sm bokstver. - Kanske vill du frst kolla i - din routers adressbok, - eller i filen i2p/hosts.txt fr att se om ditt tilltnkta namn redan r taget. - Skriv in namnet fr din eepsajt p - eepsitekonfigurationssidan fr i2ptunnel - dr det str "Website name". Detta kommer att erstta det frinstllda "mysite.i2p". - Nr du r dr, kryssa i "Auto Start"-rutan. Din eepsajt kommer nu att starta varje gng som du startar - din router. - Tryck sedan p "Save". -
  • Klicka p startknappen fr din eepsajt p - huvudkonfigurationssidan fr i2ptunnel. - Du borde nu kunna se "eepsite" listad under "Local Destinations" p vnster sida om - I2P Router Console. - Din eepsajt kr nu. -
  • Markera hela "Local destination"-nyckeln p - eepsitekonfigurationssidan fr i2ptunnel - och kopiera den fr att senare klistra in den. - Skerstll att du fr med hela texten - det r mer n 500 bokstver och den mste sluta p "AAAA". -
  • Skriv in namnet och klistra in destinationsnyckeln i din - huvudadressbok. - Klicka p "Add" fr att lgga till destinationen i din adressbok. -
  • I din webblsare, skriv in ditt eepsajtnamn (ettbranamn.i2p) s borde du landa p den hr sidan igen. - Frhoppningsvis fungerade det. -
  • Innan du berttar fr vrlden om den nya eepsajt borde du lgga till lite innehll. - G till ~/.i2p/eepsite/docroot/ (p Linux eller OS X) eller %APPDATA%\I2P\eepsite\docroot\ (p Windows) - och erstt omdirigeringssidan index.html med ditt eget innehll. Virtuella mappar fungerar, s du kan serva filer frn en - underkatalog utan att behva ge en sida med lnkar till filer. Om du behver en mall fr en enkel sajt s - varsgod och lna och anpassa - denna sida och det hr innehllet! -
-

Registrera din egen .I2P-domn

    -
  • Nu r det dags att lgga till din eepsajt till en I2P-adressbok som hostas p en sajt - som stats.i2p. - Allts, du mste skriva in namn och nyckeln p din eepsajt i ett webbgrnssnitt p - en eller flera av dessa sajter. - Hr r nyckelinmatningsformulret hos stats.i2p. - terigen, din nyckel r hela "Local destination"-nyckeln p - eepsite-konfigurationssidan fr i2ptunnel. - Skerstll att du fr med hela texten, som slutar med "AAAA". - Glm inte att klicka p "add a key". - Kolla att den rapporterar att nyckeln lagts till. - Eftersom mnga routrar periodiskt skaffar adressboksuppdateringar frn dessa sajter - s kommer andra att kunna finna din eepsajt inom ett antal timmar, bara genom att - skriva ettbranamn.i2p i sin webblsare. -

Att prenumerera p adressbcker

    -
  • P tal adressboksuppdateringar, nu vore en bra tidpunkt att lgga till ngra fler adressbcker - till din egen - prenumerationslista. - G till din prenumerationsinstllningssida och lgg till ett par av de hr fr en automatiskt uppdaterad - lista ver nya hosts: -
  • Om du har brttom och inte kan vnta ett par timmar s kan du sga t folk att anvnda en "jump"-adresshjlpar- - omdirigeringstjnst. - Detta kommer att funka inom ett par minuter efter att du skrivit in nyckeln i en adressbok p samma sajt. - Prova frst sjlv genom att skriva: - http://stats.i2p/cgi-bin/jump.cgi?a=ettbranamn.i2p eller - http://i2host.i2p/cgi-bin/i2hostjump?ettbranamn.i2p - i din webblsare. - S snart som det funkar kan du bertta fr andra att de ska anvnda det. -
  • Vissa mnniskor kolla p eepsajtlistor som - inproxy.tino.i2p/status.php efter nya eepsajter, - s att du kan brja f ett par beskare. Men det finns massor av stt att bertta fr folk. - Hr r en rad ider: - - Notera att vissa sajter rekommenderar att du klistrar in den verkligt - lnga destinationsnyckeln. Det kan du om vill - men om du har framgngsrikt har skickat din - nyckel, testat den med en "hopptjnst", och vntat 24 timmar p att adressboken ska brja - propagera sina ndringar till andra, s det borde inte vara ndvndigt.
-

Vidare assistans

-

- Ifall du har ngra frgor, s finns fljande stllen fr support: -

- -
-Note: This page, the website and the console all need translating into YOUR language if it's not already been done or in progress. Please consider helping the project grow by volunteering your time to translate. Contact the project via the IRC channel listed above. Thanks in advance!
-
-Document last edited: August 2010.
-
- + + + I2P Anonym Webbserver | Välkommen till din eepsite + + + + + +
+
+

I2P Anonym Webbserver

+
+ +English +中文 +Deutsch +Français +Nederlands +Русский +Svenska + +
+

Snabb vägledning till anonym webbservning på I2P

+ +

Det här är din eepsite, din egen anonyma I2P-webbserver - redigera bara filerna + under ~/.i2p/eepsite/docroot/ (Linux, OS X) + eller %APPDATA%\I2P\eepsite\docroot\ (Windows) + så kommer andra kunna nå dem efter att du följt instruktionerna nedan. + I I2P så adresseras eepsajter med en 'nyckel', som representeras som en väldigt lång Base64-sträng. + ('Nyckeln' är något så när analog med en IP-adress och visas + på eepsajtens I2PTunnel-konfigurationssida). + Nedan ges instruktioner om hur du kan ange ett namn som "minsajt.i2p" till din nyckel och börja köra din eepsajt.

+

Du kan nå din eepsajt lokalt via + http://127.0.0.1:7658/. +

+ +

Att sätta upp och annonsera din eepsajt

+ Din eepsajt är stoppad som standard. + Efter att du startat den kommer det att vara svårt för att andra att hitta den, + eftersom den inte har ett namn och de inte känner till din mycket långa Base64-nyckel. + Du skulle bara kunna berätta för andra om den långa nyckeln, men tacksamt nog har i2p en + adressbok och många enkla sätt att berätta för folk om din eepsajt. Här är alla stegen. +
    +
  • Välj ett namn åt din eepsajt (ettbranamn.i2p). Små bokstäver. + Kanske vill du först kolla i + din routers adressbok, + eller i filen i2p/hosts.txt för att se om ditt tilltänkta namn redan är taget. + Skriv in namnet för din eepsajt på + eepsitekonfigurationssidan för i2ptunnel + där det står "Website name". Detta kommer att ersätta det förinställda "mysite.i2p". + När du är där, kryssa i "Auto Start"-rutan. Din eepsajt kommer nu att starta varje gång som du startar + din router. + Tryck sedan på "Save". +
  • Klicka på startknappen för din eepsajt på + huvudkonfigurationssidan för i2ptunnel. + Du borde nu kunna se "eepsite" listad under "Local Destinations" på vänster sida om + I2P Router Console. + Din eepsajt kör nu. +
  • Markera hela "Local destination"-nyckeln på + eepsitekonfigurationssidan för i2ptunnel + och kopiera den för att senare klistra in den. + Säkerställ att du får med hela texten - det är mer än 500 bokstäver och den måste sluta på "AAAA". +
  • Skriv in namnet och klistra in destinationsnyckeln i din + huvudadressbok. + Klicka på "Add" för att lägga till destinationen i din adressbok. +
  • I din webbläsare, skriv in ditt eepsajtnamn (ettbranamn.i2p) så borde du landa på den här sidan igen. + Förhoppningsvis fungerade det. +
  • Innan du berättar för världen om den nya eepsajt borde du lägga till lite innehåll. + Gå till ~/.i2p/eepsite/docroot/ (på Linux eller OS X) eller %APPDATA%\I2P\eepsite\docroot\ (på Windows) + och ersätt omdirigeringssidan index.html med ditt eget innehåll. Virtuella mappar fungerar, så du kan serva filer från en + underkatalog utan att behöva ge en sida med länkar till filer. Om du behöver en mall för en enkel sajt så + varsågod och låna och anpassa + denna sida och det här innehållet! +
+

Registrera din egen .I2P-domän

    +
  • Nu är det dags att lägga till din eepsajt till en I2P-adressbok som hostas på en sajt + som stats.i2p. + Alltså, du måste skriva in namn och nyckeln på din eepsajt i ett webbgränssnitt på + en eller flera av dessa sajter. + Här är nyckelinmatningsformuläret hos stats.i2p. + Återigen, din nyckel är hela "Local destination"-nyckeln på + eepsite-konfigurationssidan för i2ptunnel. + Säkerställ att du får med hela texten, som slutar med "AAAA". + Glöm inte att klicka på "add a key". + Kolla att den rapporterar att nyckeln lagts till. + Eftersom många routrar periodiskt skaffar adressboksuppdateringar från dessa sajter + så kommer andra att kunna finna din eepsajt inom ett antal timmar, bara genom att + skriva ettbranamn.i2p i sin webbläsare. +

Att prenumerera på adressböcker

    +
  • På tal adressboksuppdateringar, nu vore en bra tidpunkt att lägga till några fler adressböcker + till din egen + prenumerationslista. + Gå till din prenumerationsinställningssida och lägg till ett par av de här för en automatiskt uppdaterad + lista över nya hosts: +
  • Om du har bråttom och inte kan vänta ett par timmar så kan du säga åt folk att använda en "jump"-adresshjälpar- + omdirigeringstjänst. + Detta kommer att funka inom ett par minuter efter att du skrivit in nyckeln i en adressbok på samma sajt. + Prova först själv genom att skriva: + http://stats.i2p/cgi-bin/jump.cgi?a=ettbranamn.i2p eller + http://i2host.i2p/cgi-bin/i2hostjump?ettbranamn.i2p + i din webbläsare. + Så snart som det funkar kan du berätta för andra att de ska använda det. +
  • Vissa människor kolla på eepsajtlistor som + inproxy.tino.i2p/status.php efter nya eepsajter, + så att du kan börja få ett par besökare. Men det finns massor av sätt att berätta för folk. + Här är en rad idëer: + + Notera att vissa sajter rekommenderar att du klistrar in den verkligt + långa destinationsnyckeln. Det kan du om vill - men om du har framgångsrikt har skickat din + nyckel, testat den med en "hopptjänst", och väntat 24 timmar på att adressboken ska börja + propagera sina ändringar till andra, så det borde inte vara nödvändigt.
+

Vidare assistans

+

+ Ifall du har några frågor, så finns följande ställen för support: +

+ +
+Note: This page, the website and the console all need translating into YOUR language if it's not already been done or in progress. Please consider helping the project grow by volunteering your time to translate. Contact the project via the IRC channel listed above. Thanks in advance!
+
+Document last edited: August 2010.
+
+ \ No newline at end of file