diff --git a/apps/addressbook/java/src/net/i2p/router/naming/BlockfileNamingService.java b/apps/addressbook/java/src/net/i2p/router/naming/BlockfileNamingService.java
index cf9f4c72c9fe62e1920c340120517aa8482f3e83..af8928e1f8b58c09b4b7256adf3bc16e25aa1ec9 100644
--- a/apps/addressbook/java/src/net/i2p/router/naming/BlockfileNamingService.java
+++ b/apps/addressbook/java/src/net/i2p/router/naming/BlockfileNamingService.java
@@ -2069,9 +2069,8 @@ public class BlockfileNamingService extends DummyNamingService {
             }
             if (baos.size() > 65535)
                 throw new DataFormatException("Properties too big (65535 max): " + baos.size());
-            byte propBytes[] = baos.toByteArray();
-            DataHelper.writeLong(rawStream, 2, propBytes.length);
-            rawStream.write(propBytes);
+            DataHelper.writeLong(rawStream, 2, baos.size());
+            baos.writeTo(rawStream);
         } else {
             DataHelper.writeLong(rawStream, 2, 0);
         }
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/Packet.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/Packet.java
index eed07853d8368145847e0ea13a6eca95e0e90e58..42c0af698afb609516b693e21bc4b2d3849bfca0 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/impl/Packet.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/Packet.java
@@ -1,7 +1,6 @@
 package net.i2p.client.streaming.impl;
 
 import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Date;
@@ -16,6 +15,7 @@ import net.i2p.data.DataHelper;
 import net.i2p.data.Destination;
 import net.i2p.data.Signature;
 import net.i2p.data.SigningPublicKey;
+import net.i2p.util.ByteArrayStream;
 import net.i2p.util.Log;
 
 /**
@@ -799,7 +799,7 @@ class Packet {
                     l.warn("Offline signature expired " + toString());
                 return false;
             }
-            ByteArrayOutputStream baos = new ByteArrayOutputStream(6 + _transientSigningPublicKey.length());
+            ByteArrayStream baos = new ByteArrayStream(6 + _transientSigningPublicKey.length());
             try {
                 DataHelper.writeLong(baos, 4, _transientExpires / 1000);
                 DataHelper.writeLong(baos, 2, _transientSigningPublicKey.getType().getCode());
@@ -809,8 +809,7 @@ class Packet {
             } catch (DataFormatException dfe) {
                 return false;
             }
-            byte[] data = baos.toByteArray();
-            boolean ok = ctx.dsa().verifySignature(_offlineSignature, data, 0, data.length, spk);
+            boolean ok = baos.verifySignature(ctx, _offlineSignature, spk);
             if (!ok) {
                 Log l = ctx.logManager().getLog(Packet.class);
                 if (l.shouldLog(Log.WARN))
@@ -915,7 +914,7 @@ class Packet {
             else
                 buf.append(" (no expiration)");
             if (_transientSigningPublicKey != null)
-                buf.append(" TRANSKEY ").append(_transientSigningPublicKey.getType());
+                buf.append(" TRANSKEY ").append(_transientSigningPublicKey.getType()).append(':').append(_transientSigningPublicKey.toBase64());
             else
                 buf.append(" (no key data)");
             if (_offlineSignature != null)
diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java
index 735259554439bf67160c8c386557ea90ecc46ee0..1e628a44ddfa5fd2599421b9a1eaf910ffcc1fdf 100644
--- a/core/java/src/net/i2p/data/DataHelper.java
+++ b/core/java/src/net/i2p/data/DataHelper.java
@@ -46,6 +46,7 @@ import java.util.zip.CRC32;
 import java.util.zip.Deflater;
 
 import net.i2p.I2PAppContext;
+import net.i2p.util.ByteArrayStream;
 import net.i2p.util.ByteCache;
 import net.i2p.util.FileUtil;
 import net.i2p.util.OrderedProperties;
@@ -283,9 +284,8 @@ public class DataHelper {
             }
             if (baos.size() > 65535)
                 throw new DataFormatException("Properties too big (65535 max): " + baos.size());
-            byte propBytes[] = baos.toByteArray();
-            writeLong(rawStream, 2, propBytes.length);
-            rawStream.write(propBytes);
+            writeLong(rawStream, 2, baos.size());
+            baos.writeTo(rawStream);
         } else {
             writeLong(rawStream, 2, 0);
         }
@@ -318,7 +318,7 @@ public class DataHelper {
                 p = new OrderedProperties();
                 p.putAll(props);
             }
-            ByteArrayOutputStream baos = new ByteArrayOutputStream(p.size() * 64);
+            ByteArrayStream baos = new ByteArrayStream(p.size() * 64);
             for (Map.Entry<Object, Object> entry : p.entrySet()) {
                 String key = (String) entry.getKey();
                 String val = (String) entry.getValue();
@@ -329,11 +329,10 @@ public class DataHelper {
             }
             if (baos.size() > 65535)
                 throw new DataFormatException("Properties too big (65535 max): " + baos.size());
-            byte propBytes[] = baos.toByteArray();
-            toLong(target, offset, 2, propBytes.length);
+            toLong(target, offset, 2, baos.size());
             offset += 2;
-            System.arraycopy(propBytes, 0, target, offset, propBytes.length);
-            offset += propBytes.length;
+            baos.copyTo(target, offset);
+            offset += baos.size();
             return offset;
         } else {
             toLong(target, offset, 2, 0);
diff --git a/core/java/src/net/i2p/data/LeaseSet2.java b/core/java/src/net/i2p/data/LeaseSet2.java
index df523efad7aa9e846d3ffd25546fb5ddad6c281f..9888b30f6f43cfa49a02285c690bfdfd429517a5 100644
--- a/core/java/src/net/i2p/data/LeaseSet2.java
+++ b/core/java/src/net/i2p/data/LeaseSet2.java
@@ -299,9 +299,7 @@ public class LeaseSet2 extends LeaseSet {
         } catch (DataFormatException dfe) {
             return null;
         }
-        byte[] data = baos.toByteArray();
-        I2PAppContext ctx = I2PAppContext.getGlobalContext();
-        return ctx.dsa().sign(data, priv);
+        return baos.sign(priv);
     }
 
     public boolean verifyOfflineSignature() {
@@ -324,8 +322,7 @@ public class LeaseSet2 extends LeaseSet {
         } catch (DataFormatException dfe) {
             return false;
         }
-        byte[] data = baos.toByteArray();
-        return ctx.dsa().verifySignature(_offlineSignature, data, 0, data.length, getSigningPublicKey());
+        return baos.verifySignature(ctx, _offlineSignature, getSigningPublicKey());
     }
 
     /**
@@ -613,9 +610,8 @@ public class LeaseSet2 extends LeaseSet {
         } catch (IOException ioe) {
             throw new DataFormatException("Signature failed", ioe);
         }
-        byte data[] = out.toByteArray();
         // now sign with the key 
-        _signature = DSAEngine.getInstance().sign(data, key);
+        _signature = out.sign(key);
         if (_signature == null)
             throw new DataFormatException("Signature failed with " + key.getType() + " key");
     }
@@ -659,8 +655,7 @@ public class LeaseSet2 extends LeaseSet {
             dfe.printStackTrace();
             return false;
         }
-        byte data[] = out.toByteArray();
-        return DSAEngine.getInstance().verifySignature(_signature, data, spk);
+        return out.verifySignature(_signature, spk);
     }
     
     @Override
diff --git a/core/java/src/net/i2p/data/i2cp/SessionConfig.java b/core/java/src/net/i2p/data/i2cp/SessionConfig.java
index a138e6aaaf8aa3652b2094b762e30aa1a545ec1c..75435be17ce74b737f0c574d97a1519ebb212ce9 100644
--- a/core/java/src/net/i2p/data/i2cp/SessionConfig.java
+++ b/core/java/src/net/i2p/data/i2cp/SessionConfig.java
@@ -289,9 +289,7 @@ public class SessionConfig extends DataStructureImpl {
             } catch (DataFormatException dfe) {
                 return false;
             }
-            byte[] odata = baos.toByteArray();
-            boolean ok = DSAEngine.getInstance().verifySignature(sig, odata, 0, odata.length,
-                                                                 _destination.getSigningPublicKey());
+            boolean ok = baos.verifySignature(sig, _destination.getSigningPublicKey());
             if (!ok)
                 return false;
         } else {
diff --git a/core/java/src/net/i2p/util/ByteArrayStream.java b/core/java/src/net/i2p/util/ByteArrayStream.java
index 6fd3c1ffb0adc8114ebe31d36dbc740a99f6eead..c4de782713d2cb937fe792091cfa2e91cbf87d22 100644
--- a/core/java/src/net/i2p/util/ByteArrayStream.java
+++ b/core/java/src/net/i2p/util/ByteArrayStream.java
@@ -4,6 +4,12 @@ import java.io.ByteArrayOutputStream;
 import java.io.ByteArrayInputStream;
 import java.util.Arrays;
 
+import net.i2p.I2PAppContext;
+import net.i2p.crypto.DSAEngine;
+import net.i2p.data.Signature;
+import net.i2p.data.SigningPrivateKey;
+import net.i2p.data.SigningPublicKey;
+
 /**
  *  OutputStream to InputStream adapter.
  *  Zero-copy where possible. Unsynchronized.
@@ -52,4 +58,41 @@ public class ByteArrayStream extends ByteArrayOutputStream {
     public ByteArrayInputStream asInputStream() {
         return new ByteArrayInputStream(buf, 0, count);
     }
+
+    /**
+     *  Copy all data to the target
+     */
+    public void copyTo(byte[] target, int offset) {
+        System.arraycopy(buf, 0, target, offset, count);
+    }
+
+    /**
+     *  Verify the written data
+     */
+    public boolean verifySignature(Signature signature, SigningPublicKey verifyingKey) {
+        return DSAEngine.getInstance().verifySignature(signature, buf, 0, count, verifyingKey);
+    }
+
+    /**
+     *  Verify the written data
+     */
+    public boolean verifySignature(I2PAppContext ctx, Signature signature, SigningPublicKey verifyingKey) {
+        return ctx.dsa().verifySignature(signature, buf, 0, count, verifyingKey);
+    }
+
+    /**
+     *  Sign the written data
+     *  @return null on error
+     */
+    public Signature sign(SigningPrivateKey signingKey) {
+        return DSAEngine.getInstance().sign(buf, 0, count, signingKey);
+    }
+
+    /**
+     *  Sign the written data
+     *  @return null on error
+     */
+    public Signature sign(I2PAppContext ctx, SigningPrivateKey signingKey) {
+        return ctx.dsa().sign(buf, 0, count, signingKey);
+    }
 }