diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
index 869af99900e20831e6f3eeb90279d4a1f59933fc..dee3f88c11336506849c47e5eae488b59b5a573f 100644
--- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
+++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
@@ -100,9 +100,16 @@ class OutboundMessageState implements CDPQEntry {
         else
             _i2npMessage.toRawByteArray(_messageBuf);
         _fragmentSize = _peer.fragmentSize();
-        int numFragments = totalSize / _fragmentSize;
-        if (numFragments * _fragmentSize < totalSize)
-            numFragments++;
+        // SSU2 first frag can be 5 bytes bigger
+        int first = _fragmentSize;
+        if (peer.getVersion() > 1)
+            first += SSU2Util.DATA_FOLLOWON_EXTRA_SIZE;
+        int numFragments = 1;
+        if (first < totalSize) {
+            numFragments += (totalSize - first) / _fragmentSize;
+            if (first + ((numFragments - 1) * _fragmentSize) < totalSize)
+                numFragments++;
+        }
         // This should never happen, as 534 bytes * 64 fragments > 32KB, and we won't bid on > 32KB
         if (numFragments > InboundMessageState.MAX_FRAGMENTS)
             throw new IllegalArgumentException("Fragmenting a " + totalSize + " message into " + numFragments + " fragments - too many!");
@@ -441,19 +448,23 @@ class OutboundMessageState implements CDPQEntry {
 
     /**
      * The size in bytes of the fragment.
-     * Does NOT include any SSU overhead.
+     * Does NOT include any SSU overhead (SSU2 is 3 for all fragments, + 5 for followon fragments)
      *
      * @param fragmentNum the number of the fragment
      * @return the size of the fragment specified by the number
      */
     public int fragmentSize(int fragmentNum) {
-        if (fragmentNum + 1 == _numFragments) {
-            int valid = _messageBuf.length;
-            if (valid <= _fragmentSize)
-                return valid;
-            // bugfix 0.8.12
-            int mod = valid % _fragmentSize;
-            return mod == 0 ? _fragmentSize : mod;
+        if (fragmentNum == 0) {
+            // SSU2 first frag is 5 bytes bigger
+            int fs = _fragmentSize;
+            if (_peer.getVersion() > 1)
+                fs += SSU2Util.DATA_FOLLOWON_EXTRA_SIZE;
+            return Math.min(_messageBuf.length, fs);
+        } else if (fragmentNum + 1 == _numFragments) {
+            int last = _messageBuf.length - (fragmentNum * _fragmentSize);
+            if (_peer.getVersion() > 1)
+                last -= SSU2Util.DATA_FOLLOWON_EXTRA_SIZE;
+            return last;
         } else {
             return _fragmentSize;
         }
@@ -469,6 +480,9 @@ class OutboundMessageState implements CDPQEntry {
      */
     public int writeFragment(byte out[], int outOffset, int fragmentNum) {
         int start = _fragmentSize * fragmentNum;
+        // SSU2 first frag is 5 bytes bigger
+        if (fragmentNum > 0 && _peer.getVersion() > 1)
+            start += SSU2Util.DATA_FOLLOWON_EXTRA_SIZE;
         int toSend = fragmentSize(fragmentNum);
         int end = start + toSend;
         if (end <= _messageBuf.length && outOffset + toSend <= out.length) {