diff --git a/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java b/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java
index 3d205861138bf2113ec334444ab9fcf915331056..8886faf7227b4d9cae3bc0855fe8119dd51085ad 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java
@@ -12,6 +12,7 @@ import com.southernstorm.noise.protocol.CipherState;
 import com.southernstorm.noise.protocol.CipherStatePair;
 import com.southernstorm.noise.protocol.HandshakeState;
 
+import net.i2p.crypto.HKDF;
 import net.i2p.data.Base64;
 import net.i2p.data.DataFormatException;
 import net.i2p.data.DataHelper;
@@ -436,33 +437,24 @@ class OutboundNTCP2State implements EstablishState {
     static byte[][] generateSipHashKeys(RouterContext ctx, HandshakeState state) {
         // TODO use noise HMAC or HKDF method instead?
         // ask_master = HKDF(ck, zerolen, info="ask")
-        byte[] temp_key = doHMAC(ctx, state.getChainingKey(), ZEROLEN);
-        byte[] ask_master = doHMAC(ctx, temp_key, ASK);
+        HKDF hkdf = new HKDF(ctx);
+        byte[] ask_master = new byte[32];
+        hkdf.calculate(state.getChainingKey(), ZEROLEN, "ask", ask_master);
         byte[] tmp = new byte[32 + SIPHASH.length];
         byte[] hash = state.getHandshakeHash();
         System.arraycopy(hash, 0, tmp, 0, 32);
         System.arraycopy(SIPHASH, 0, tmp, 32, SIPHASH.length); 
-        temp_key = doHMAC(ctx, ask_master, tmp);
-        byte[] sip_master = doHMAC(ctx, temp_key, ONE);
-        temp_key = doHMAC(ctx, sip_master, ZEROLEN);
-        // Output 1
-        byte[] sip_ab = doHMAC(ctx, temp_key, ONE);
-        // Output 2
-        tmp = new byte[KEY_SIZE + 1];
-        System.arraycopy(sip_ab, 0, tmp, 0, 32);
-        tmp[32] = 2;
-        byte[] sip_ba = doHMAC(ctx, temp_key, tmp);
-        Arrays.fill(temp_key, (byte) 0);
+        byte[] sip_master = new byte[32];
+        hkdf.calculate(ask_master, tmp, sip_master);
+        Arrays.fill(ask_master, (byte) 0);
         Arrays.fill(tmp, (byte) 0);
+        byte[] sip_ab = new byte[32];
+        byte[] sip_ba = new byte[32];
+        hkdf.calculate(sip_master, ZEROLEN, sip_ab, sip_ba, 0);
+        Arrays.fill(sip_master, (byte) 0);
         return new byte[][] { sip_ab, sip_ba };
     }
 
-    private static byte[] doHMAC(RouterContext ctx, byte[] key, byte[] data) {
-        byte[] rv = new byte[32];
-        ctx.hmac256().calculate(key, data, 0, data.length, rv, 0);
-        return rv;
-    }
-
     /**
      *  Release resources on timeout.
      *  @param e may be null