diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java
index e880d5a19ebb51b24eca9c2dd76ace8b27a71a3f..39b388443a5dbcd4b3f3d94e500b03d76d7d9aac 100644
--- a/core/java/src/net/i2p/I2PAppContext.java
+++ b/core/java/src/net/i2p/I2PAppContext.java
@@ -13,7 +13,6 @@ import net.i2p.client.naming.NamingService;
 import net.i2p.crypto.AESEngine;
 import net.i2p.crypto.CryptixAESEngine;
 import net.i2p.crypto.DSAEngine;
-import net.i2p.crypto.ElGamalAESEngine;
 import net.i2p.crypto.ElGamalEngine;
 import net.i2p.crypto.HMAC256Generator;
 import net.i2p.crypto.HMACGenerator;
@@ -74,7 +73,6 @@ public class I2PAppContext {
     protected SessionKeyManager _sessionKeyManager;
     private NamingService _namingService;
     private ElGamalEngine _elGamalEngine;
-    private ElGamalAESEngine _elGamalAESEngine;
     private AESEngine _AESEngine;
     private LogManager _logManager;
     private HMACGenerator _hmac;
@@ -94,7 +92,6 @@ public class I2PAppContext {
     protected volatile boolean _sessionKeyManagerInitialized;
     private volatile boolean _namingServiceInitialized;
     private volatile boolean _elGamalEngineInitialized;
-    private volatile boolean _elGamalAESEngineInitialized;
     private volatile boolean _AESEngineInitialized;
     private volatile boolean _logManagerInitialized;
     private volatile boolean _hmacInitialized;
@@ -120,7 +117,7 @@ public class I2PAppContext {
     private final ClientAppManager _appManager;
     // split up big lock on this to avoid deadlocks
     private final Object _lock1 = new Object(), _lock2 = new Object(), _lock3 = new Object(), _lock4 = new Object(),
-                         _lock5 = new Object(), _lock6 = new Object(), _lock7 = new Object(), _lock8 = new Object(),
+                         _lock5 = new Object(), _lock7 = new Object(), _lock8 = new Object(),
                          _lock9 = new Object(), _lock10 = new Object(), _lock11 = new Object(), _lock12 = new Object(),
                          _lock13 = new Object(), _lock14 = new Object(), _lock16 = new Object(),
                          _lock17 = new Object(), _lock18 = new Object(), _lock19 = new Object(), _lock20 = new Object();
@@ -681,28 +678,7 @@ public class I2PAppContext {
             _elGamalEngineInitialized = true;
         }
     }
-    
-    /**
-     * Access the ElGamal/AES+SessionTag engine for this context.  The algorithm
-     * makes use of the context's sessionKeyManager to coordinate transparent
-     * access to the sessionKeys and sessionTags, as well as the context's elGamal
-     * engine (which in turn keeps stats, etc).
-     *
-     */
-    public ElGamalAESEngine elGamalAESEngine() {
-        if (!_elGamalAESEngineInitialized)
-            initializeElGamalAESEngine();
-        return _elGamalAESEngine;
-    }
 
-    private void initializeElGamalAESEngine() {
-        synchronized (_lock6) {
-            if (_elGamalAESEngine == null)
-                _elGamalAESEngine = new ElGamalAESEngine(this);
-            _elGamalAESEngineInitialized = true;
-        }
-    }
-    
     /**
      * Ok, I'll admit it.  there is no good reason for having a context specific
      * AES engine.  We dont really keep stats on it, since its just too fast to
diff --git a/core/java/src/net/i2p/client/impl/I2CPMessageProducer.java b/core/java/src/net/i2p/client/impl/I2CPMessageProducer.java
index 75e6b1ebae459e3a1c57ec67e47a79807a3c9594..545a36eb9afbb060dbd6f9846acb7d1d2d8aea88 100644
--- a/core/java/src/net/i2p/client/impl/I2CPMessageProducer.java
+++ b/core/java/src/net/i2p/client/impl/I2CPMessageProducer.java
@@ -164,7 +164,7 @@ class I2CPMessageProducer {
         }
         msg.setSessionId(sid);
         msg.setNonce(nonce);
-        Payload data = createPayload(dest, payload, null, null, null, null);
+        Payload data = createPayload(payload);
         msg.setPayload(data);
         session.sendMessage(msg);
     }
@@ -191,7 +191,7 @@ class I2CPMessageProducer {
         }
         msg.setSessionId(sid);
         msg.setNonce(nonce);
-        Payload data = createPayload(dest, payload, null, null, null, null);
+        Payload data = createPayload(payload);
         msg.setPayload(data);
         session.sendMessage(msg);
     }
@@ -299,41 +299,14 @@ class I2CPMessageProducer {
         }
     }
     
-    /** 
-     * Should we include the I2CP end to end crypto (which is in addition to any
-     * garlic crypto added by the router)
-     *
-     */
-    static final boolean END_TO_END_CRYPTO = false;
-    
     /**
-     * Create a new signed payload and send it off to the destination
-     *
-     * @param tag unused - no end-to-end crypto
-     * @param tags unused - no end-to-end crypto
-     * @param key unused - no end-to-end crypto
-     * @param newKey unused - no end-to-end crypto
+     * Create a new payload.
+     * No more end-to-end encryption, just set the "encrypted" data to the payload.
      */
-    private Payload createPayload(Destination dest, byte[] payload, SessionTag tag, SessionKey key, Set<SessionTag> tags,
-                                  SessionKey newKey) throws I2PSessionException {
-        if (dest == null) throw new I2PSessionException("No destination specified");
+    private static Payload createPayload(byte[] payload) throws I2PSessionException {
         if (payload == null) throw new I2PSessionException("No payload specified");
-
         Payload data = new Payload();
-        if (!END_TO_END_CRYPTO) {
-            data.setEncryptedData(payload);
-            return data;
-        }
-        // no padding at this level
-        // the garlic may pad, and the tunnels may pad, and the transports may pad
-        int size = payload.length;
-        byte encr[] = _context.elGamalAESEngine().encrypt(payload, dest.getPublicKey(), key, tags, tag, newKey, size);
-        // yes, in an intelligent component, newTags would be queued for confirmation along with key, and
-        // generateNewTags would only generate tags if necessary
-
-        data.setEncryptedData(encr);
-        //_log.debug("Encrypting the payload to public key " + dest.getPublicKey().toBase64() + "\nPayload: "
-        //           + data.calculateHash());
+        data.setEncryptedData(payload);
         return data;
     }
 
diff --git a/core/java/src/net/i2p/crypto/AESEngine.java b/core/java/src/net/i2p/crypto/AESEngine.java
index 05e77d6bfce1a0a05cf0e876d0c72c6d929fc834..f598ec77f4ed11d6bd86662c43fe5b2923bab990 100644
--- a/core/java/src/net/i2p/crypto/AESEngine.java
+++ b/core/java/src/net/i2p/crypto/AESEngine.java
@@ -79,7 +79,7 @@ public class AESEngine {
         int size = Hash.HASH_LENGTH 
                  + 4 // sizeof(payload)
                  + payload.length;
-        int padding = ElGamalAESEngine.getPaddingSize(size, paddedSize);
+        int padding = getPaddingSize(size, paddedSize);
         
         byte data[] = new byte[size + padding];
         _context.sha().calculateHash(iv, 0, 16, data, 0);
@@ -89,7 +89,7 @@ public class AESEngine {
         cur += 4;
         System.arraycopy(payload, 0, data, cur, payload.length);
         cur += payload.length;
-        byte paddingData[] = ElGamalAESEngine.getPadding(_context, size, paddedSize);
+        byte paddingData[] = getPadding(_context, size, paddedSize);
         System.arraycopy(paddingData, 0, data, cur, paddingData.length);
         
         encrypt(data, 0, data, 0, sessionKey, iv, data.length);
@@ -182,7 +182,44 @@ public class AESEngine {
     public void decryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte rv[], int outIndex) {
         System.arraycopy(payload, inIndex, rv, outIndex, rv.length - outIndex);
     }
-    
+
+    /**
+     * Return random bytes for padding the data to a mod 16 size so that it is
+     * at least minPaddedSize
+     *
+     * Public for ElGamalAESEngine.
+     * Not a public API, not for external use.
+     *
+     * @since 0.9.38 moved from ElGamalAESEngine
+     */
+    public final static byte[] getPadding(I2PAppContext context, int curSize, long minPaddedSize) {
+        int size = getPaddingSize(curSize, minPaddedSize);
+        byte rv[] = new byte[size];
+        context.random().nextBytes(rv);
+        return rv;
+    }
+
+    /**
+     * Return size for padding the data to a mod 16 size so that it is
+     * at least minPaddedSize
+     *
+     * Public for ElGamalAESEngine.
+     * Not a public API, not for external use.
+     *
+     * @since 0.9.38 moved from ElGamalAESEngine
+     */
+    public final static int getPaddingSize(int curSize, long minPaddedSize) {
+        int diff = 0;
+        if (curSize < minPaddedSize) {
+            diff = (int) minPaddedSize - curSize;
+        }
+
+        int numPadding = diff;
+        if (((curSize + diff) % 16) != 0) numPadding += (16 - ((curSize + diff) % 16));
+        return numPadding;
+    }
+
+ 
 /******
     public static void main(String args[]) {
         I2PAppContext ctx = new I2PAppContext();
diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java
index 47766551e35efd5cd8862b0e651b6e49b5f88671..a55b5f1289fa32bd808ccbabd34ae5ffda623657 100644
--- a/router/java/src/net/i2p/router/RouterContext.java
+++ b/router/java/src/net/i2p/router/RouterContext.java
@@ -15,6 +15,7 @@ import net.i2p.data.router.RouterInfo;
 import net.i2p.data.router.RouterKeyGenerator;
 import net.i2p.internal.InternalClientManager;
 import net.i2p.router.client.ClientManagerFacadeImpl;
+import net.i2p.router.crypto.ElGamalAESEngine;
 import net.i2p.router.crypto.TransientSessionKeyManager;
 import net.i2p.router.dummy.*;
 import net.i2p.router.message.GarlicMessageParser;
@@ -68,6 +69,7 @@ public class RouterContext extends I2PAppContext {
     private RouterAppManager _appManager;
     private RouterKeyGenerator _routingKeyGenerator;
     private GarlicMessageParser _garlicMessageParser;
+    private ElGamalAESEngine _elGamalAESEngine;
     private final Set<Runnable> _finalShutdownTasks;
     // split up big lock on this to avoid deadlocks
     private volatile boolean _initialized;
@@ -211,6 +213,7 @@ public class RouterContext extends I2PAppContext {
             _clientManagerFacade = new DummyClientManagerFacade(this);
             // internal client manager is null
         }
+        _elGamalAESEngine = new ElGamalAESEngine(this);
         _garlicMessageParser = new GarlicMessageParser(this);
         _clientMessagePool = new ClientMessagePool(this);
         _jobQueue = new JobQueue(this);
@@ -667,4 +670,16 @@ public class RouterContext extends I2PAppContext {
     public GarlicMessageParser garlicMessageParser() {
         return _garlicMessageParser;
     }
+
+    /**
+     * Access the ElGamal/AES+SessionTag engine for this context.  The algorithm
+     * makes use of the context's sessionKeyManager to coordinate transparent
+     * access to the sessionKeys and sessionTags, as well as the context's elGamal
+     * engine (which in turn keeps stats, etc).
+     *
+     * @since 0.9.38 moved from superclass (app context)
+     */
+    public ElGamalAESEngine elGamalAESEngine() {
+        return _elGamalAESEngine;
+    }
 }
diff --git a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java b/router/java/src/net/i2p/router/crypto/ElGamalAESEngine.java
similarity index 97%
rename from core/java/src/net/i2p/crypto/ElGamalAESEngine.java
rename to router/java/src/net/i2p/router/crypto/ElGamalAESEngine.java
index b3e7d05ec20c79c61b42fa2d275e4e0765396ee8..8e4ac8d7f625dfc2cbc1d1f33283a6ca144afe84 100644
--- a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java
+++ b/router/java/src/net/i2p/router/crypto/ElGamalAESEngine.java
@@ -1,4 +1,4 @@
-package net.i2p.crypto;
+package net.i2p.router.crypto;
 
 /*
  * free (adj.): unencumbered; not under the control of others
@@ -16,6 +16,8 @@ import java.util.List;
 import java.util.Set;
 
 import net.i2p.I2PAppContext;
+import net.i2p.crypto.AESEngine;
+import net.i2p.crypto.SessionKeyManager;
 import net.i2p.data.DataFormatException;
 import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
@@ -31,6 +33,8 @@ import net.i2p.util.SimpleByteCache;
  * supplied keys and data.
  *
  * No, this does not extend AESEngine or CryptixAESEngine.
+ *
+ * @since 0.9.38 moved from net.i2p.crypto
  */
 public final class ElGamalAESEngine {
     private final Log _log;
@@ -649,7 +653,7 @@ public final class ElGamalAESEngine {
                  + Hash.HASH_LENGTH
                  + (newKey == null ? 1 : 1 + SessionKey.KEYSIZE_BYTES)
                  + data.length;
-        int totalSize = size + getPaddingSize(size, paddedSize);
+        int totalSize = size + AESEngine.getPaddingSize(size, paddedSize);
 
         byte aesData[] = new byte[totalSize + prefixBytes];
 
@@ -683,7 +687,7 @@ public final class ElGamalAESEngine {
         cur += data.length;
 
         //_log.debug("raw data written: " + len);
-        byte padding[] = getPadding(_context, size, paddedSize);
+        byte padding[] = AESEngine.getPadding(_context, size, paddedSize);
         //_log.debug("padding length: " + padding.length);
         System.arraycopy(padding, 0, aesData, cur, padding.length);
         cur += padding.length;
@@ -696,28 +700,6 @@ public final class ElGamalAESEngine {
         return aesData;
     }
 
-    /**
-     * Return random bytes for padding the data to a mod 16 size so that it is
-     * at least minPaddedSize
-     *
-     */
-    final static byte[] getPadding(I2PAppContext context, int curSize, long minPaddedSize) {
-        int size = getPaddingSize(curSize, minPaddedSize);
-        byte rv[] = new byte[size];
-        context.random().nextBytes(rv);
-        return rv;
-    }
-
-    final static int getPaddingSize(int curSize, long minPaddedSize) {
-        int diff = 0;
-        if (curSize < minPaddedSize) {
-            diff = (int) minPaddedSize - curSize;
-        }
-
-        int numPadding = diff;
-        if (((curSize + diff) % 16) != 0) numPadding += (16 - ((curSize + diff) % 16));
-        return numPadding;
-    }
 
 /****
     public static void main(String args[]) {
diff --git a/router/java/src/net/i2p/router/message/GarlicMessageParser.java b/router/java/src/net/i2p/router/message/GarlicMessageParser.java
index ef0e5f0b7afe7f41ea3556eddafa2d1d6da46f64..34151064c99f4a3c8c1a31e0b5d7536ed124ca06 100644
--- a/router/java/src/net/i2p/router/message/GarlicMessageParser.java
+++ b/router/java/src/net/i2p/router/message/GarlicMessageParser.java
@@ -10,7 +10,6 @@ package net.i2p.router.message;
 
 import java.util.Date;
 
-import net.i2p.I2PAppContext;
 import net.i2p.crypto.SessionKeyManager;
 import net.i2p.data.Certificate;
 import net.i2p.data.DataFormatException;
@@ -18,6 +17,7 @@ import net.i2p.data.DataHelper;
 import net.i2p.data.PrivateKey;
 import net.i2p.data.i2np.GarlicClove;
 import net.i2p.data.i2np.GarlicMessage;
+import net.i2p.router.RouterContext;
 import net.i2p.util.Log;
 
 /**
@@ -27,7 +27,7 @@ import net.i2p.util.Log;
  */
 public class GarlicMessageParser {
     private final Log _log;
-    private final I2PAppContext _context;
+    private final RouterContext _context;
     
     /**
      *  Huge limit just to reduce chance of trouble. Typ. usage is 3.
@@ -35,7 +35,7 @@ public class GarlicMessageParser {
      */
     private static final int MAX_CLOVES = 32;
 
-    public GarlicMessageParser(I2PAppContext context) { 
+    public GarlicMessageParser(RouterContext context) { 
         _context = context;
         _log = _context.logManager().getLog(GarlicMessageParser.class);
     }